1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
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.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 * $Id: memdebug.c,v 1.1.1.1 2008-09-23 16:32:05 hoffman Exp $
22 ***************************************************************************/
27 #include <curl/curl.h>
29 #ifdef HAVE_SYS_SOCKET_H
30 #include <sys/socket.h>
33 #define _MPRINTF_REPLACE
34 #include <curl/mprintf.h>
44 #define MEMDEBUG_NODEFINES /* don't redefine the standard functions */
54 /* I'm hoping this is the thing with the strictest alignment
55 * requirements. That also means we waste some space :-( */
59 * Note that these debug functions are very simple and they are meant to
60 * remain so. For advanced analysis, record a log file and write perl scripts
63 * Don't use these with multithreaded test programs!
66 #define logfile curl_debuglogfile
67 FILE *curl_debuglogfile
= NULL
;
68 static bool memlimit
= FALSE
; /* enable memory limit */
69 static long memsize
= 0; /* set number of mallocs allowed */
71 /* this sets the log file name */
72 void curl_memdebug(const char *logname
)
76 logfile
= fopen(logname
, "w");
79 #ifdef MEMDEBUG_LOG_SYNC
80 /* Flush the log file after every line so the log isn't lost in a crash */
81 setvbuf(logfile
, (char *)NULL
, _IOLBF
, 0);
86 /* This function sets the number of malloc() calls that should return
88 void curl_memlimit(long limit
)
96 /* returns TRUE if this isn't allowed! */
97 static bool countcheck(const char *func
, int line
, const char *source
)
99 /* if source is NULL, then the call is made internally and this check
100 should not be made */
101 if(memlimit
&& source
) {
103 if(logfile
&& source
)
104 fprintf(logfile
, "LIMIT %s:%d %s reached memlimit\n",
107 fprintf(stderr
, "LIMIT %s:%d %s reached memlimit\n",
110 return TRUE
; /* RETURN ERROR! */
113 memsize
--; /* countdown */
115 /* log the countdown */
116 if(logfile
&& source
)
117 fprintf(logfile
, "LIMIT %s:%d %ld ALLOCS left\n",
118 source
, line
, memsize
);
122 return FALSE
; /* allow this */
125 void *curl_domalloc(size_t wantedsize
, int line
, const char *source
)
127 struct memdebug
*mem
;
130 if(countcheck("malloc", line
, source
))
133 /* alloc at least 64 bytes */
134 size
= sizeof(struct memdebug
)+wantedsize
;
136 mem
=(struct memdebug
*)(Curl_cmalloc
)(size
);
138 /* fill memory with junk */
139 memset(mem
->mem
, 0xA5, wantedsize
);
140 mem
->size
= wantedsize
;
143 if(logfile
&& source
)
144 fprintf(logfile
, "MEM %s:%d malloc(%zd) = %p\n",
145 source
, line
, wantedsize
, mem
? mem
->mem
: 0);
146 return (mem
? mem
->mem
: NULL
);
149 void *curl_docalloc(size_t wanted_elements
, size_t wanted_size
,
150 int line
, const char *source
)
152 struct memdebug
*mem
;
153 size_t size
, user_size
;
155 if(countcheck("calloc", line
, source
))
158 /* alloc at least 64 bytes */
159 user_size
= wanted_size
* wanted_elements
;
160 size
= sizeof(struct memdebug
) + user_size
;
162 mem
= (struct memdebug
*)(Curl_cmalloc
)(size
);
164 /* fill memory with zeroes */
165 memset(mem
->mem
, 0, user_size
);
166 mem
->size
= user_size
;
169 if(logfile
&& source
)
170 fprintf(logfile
, "MEM %s:%d calloc(%u,%u) = %p\n",
171 source
, line
, wanted_elements
, wanted_size
, mem
? mem
->mem
: 0);
172 return (mem
? mem
->mem
: NULL
);
175 char *curl_dostrdup(const char *str
, int line
, const char *source
)
180 DEBUGASSERT(str
!= NULL
);
182 if(countcheck("strdup", line
, source
))
187 mem
=curl_domalloc(len
, 0, NULL
); /* NULL prevents logging */
189 memcpy(mem
, str
, len
);
192 fprintf(logfile
, "MEM %s:%d strdup(%p) (%zd) = %p\n",
193 source
, line
, str
, len
, mem
);
198 /* We provide a realloc() that accepts a NULL as pointer, which then
199 performs a malloc(). In order to work with ares. */
200 void *curl_dorealloc(void *ptr
, size_t wantedsize
,
201 int line
, const char *source
)
203 struct memdebug
*mem
=NULL
;
205 size_t size
= sizeof(struct memdebug
)+wantedsize
;
207 if(countcheck("realloc", line
, source
))
211 mem
= (struct memdebug
*)((char *)ptr
- offsetof(struct memdebug
, mem
));
213 mem
=(struct memdebug
*)(Curl_crealloc
)(mem
, size
);
215 fprintf(logfile
, "MEM %s:%d realloc(%p, %zd) = %p\n",
216 source
, line
, ptr
, wantedsize
, mem
?mem
->mem
:NULL
);
219 mem
->size
= wantedsize
;
226 void curl_dofree(void *ptr
, int line
, const char *source
)
228 struct memdebug
*mem
;
230 DEBUGASSERT(ptr
!= NULL
);
232 mem
= (struct memdebug
*)((char *)ptr
- offsetof(struct memdebug
, mem
));
235 memset(mem
->mem
, 0x13, mem
->size
);
241 fprintf(logfile
, "MEM %s:%d free(%p)\n", source
, line
, ptr
);
244 int curl_socket(int domain
, int type
, int protocol
, int line
,
247 int sockfd
=(socket
)(domain
, type
, protocol
);
248 if(logfile
&& (sockfd
!=-1))
249 fprintf(logfile
, "FD %s:%d socket() = %d\n",
250 source
, line
, sockfd
);
254 int curl_accept(int s
, void *saddr
, void *saddrlen
,
255 int line
, const char *source
)
257 struct sockaddr
*addr
= (struct sockaddr
*)saddr
;
258 socklen_t
*addrlen
= (socklen_t
*)saddrlen
;
259 int sockfd
=(accept
)(s
, addr
, addrlen
);
261 fprintf(logfile
, "FD %s:%d accept() = %d\n",
262 source
, line
, sockfd
);
266 /* this is our own defined way to close sockets on *ALL* platforms */
267 int curl_sclose(int sockfd
, int line
, const char *source
)
269 int res
=sclose(sockfd
);
271 fprintf(logfile
, "FD %s:%d sclose(%d)\n",
272 source
, line
, sockfd
);
276 FILE *curl_fopen(const char *file
, const char *mode
,
277 int line
, const char *source
)
279 FILE *res
=(fopen
)(file
, mode
);
281 fprintf(logfile
, "FILE %s:%d fopen(\"%s\",\"%s\") = %p\n",
282 source
, line
, file
, mode
, res
);
286 FILE *curl_fdopen(int filedes
, const char *mode
,
287 int line
, const char *source
)
289 FILE *res
=(fdopen
)(filedes
, mode
);
291 fprintf(logfile
, "FILE %s:%d fdopen(\"%d\",\"%s\") = %p\n",
292 source
, line
, filedes
, mode
, res
);
296 int curl_fclose(FILE *file
, int line
, const char *source
)
300 DEBUGASSERT(file
!= NULL
);
304 fprintf(logfile
, "FILE %s:%d fclose(%p)\n",
310 int VOID_VAR_MEMDEBUG
;
312 /* we provide a fake do-nothing function here to avoid compiler warnings */
313 void curl_memdebug(void) {}
315 #endif /* CURLDEBUG */