= CRYPTO_free;
#ifndef OPENSSL_NO_CRYPTO_MDEBUG
+static int malloc_count;
+static int realloc_count;
+static int free_count;
+static int dummy;
+
+# define INCREMENT(x) CRYPTO_atomic_add(&x, 1, &dummy, memdbg_lock)
+# define GET(ret, val) CRYPTO_atomic_read(&val, ret, memdbg_lock)
+
static char *md_failstring;
static long md_count;
static int md_fail_percent = 0;
#else
static int call_malloc_debug = 0;
+# define INCREMENT(x) /* empty */
# define FAILTEST() /* empty */
#endif
}
#ifndef OPENSSL_NO_CRYPTO_MDEBUG
+void CRYPTO_get_alloc_counts(int *mcount, int *rcount, int *fcount)
+{
+ if (mcount != NULL)
+ GET(mcount, malloc_count);
+ if (rcount != NULL)
+ GET(rcount, realloc_count);
+ if (fcount != NULL)
+ GET(fcount, free_count);
+}
+
/*
* Parse a "malloc failure spec" string. This likes like a set of fields
* separated by semicolons. Each field has a count and an optional failure
{
void *ret = NULL;
+ INCREMENT(malloc_count);
if (malloc_impl != NULL && malloc_impl != CRYPTO_malloc)
return malloc_impl(num, file, line);
void *CRYPTO_realloc(void *str, size_t num, const char *file, int line)
{
+ INCREMENT(realloc_count);
if (realloc_impl != NULL && realloc_impl != &CRYPTO_realloc)
return realloc_impl(str, num, file, line);
void CRYPTO_free(void *str, const char *file, int line)
{
+ INCREMENT(free_count);
if (free_impl != NULL && free_impl != &CRYPTO_free) {
free_impl(str, file, line);
return;
};
static CRYPTO_ONCE memdbg_init = CRYPTO_ONCE_STATIC_INIT;
-static CRYPTO_RWLOCK *malloc_lock = NULL;
-static CRYPTO_RWLOCK *long_malloc_lock = NULL;
+CRYPTO_RWLOCK *memdbg_lock;
+static CRYPTO_RWLOCK *long_memdbg_lock;
static CRYPTO_THREAD_LOCAL appinfokey;
/* memory-block description */
#endif
};
-static LHASH_OF(MEM) *mh = NULL; /* hash-table of memory requests (address as
- * key); access requires MALLOC2 lock */
+/*
+ * hash-table of memory requests (address as * key); access requires
+ * long_memdbg_lock lock
+ */
+static LHASH_OF(MEM) *mh = NULL;
/* num_disable > 0 iff mh_mode == CRYPTO_MEM_CHECK_ON (w/o ..._ENABLE) */
static unsigned int num_disable = 0;
/*
- * Valid iff num_disable > 0. long_malloc_lock is locked exactly in this
+ * Valid iff num_disable > 0. long_memdbg_lock is locked exactly in this
* case (by the thread named in disabling_thread).
*/
static CRYPTO_THREAD_ID disabling_threadid;
DEFINE_RUN_ONCE_STATIC(do_memdbg_init)
{
- malloc_lock = CRYPTO_THREAD_glock_new("malloc");
- long_malloc_lock = CRYPTO_THREAD_glock_new("long_malloc");
- if (malloc_lock == NULL || long_malloc_lock == NULL
- || !CRYPTO_THREAD_init_local(&appinfokey, NULL)) {
- CRYPTO_THREAD_lock_free(malloc_lock);
- malloc_lock = NULL;
- CRYPTO_THREAD_lock_free(long_malloc_lock);
- long_malloc_lock = NULL;
+ memdbg_lock = CRYPTO_THREAD_glock_new("malloc");
+ long_memdbg_lock = CRYPTO_THREAD_glock_new("long_malloc");
+ if (memdbg_lock == NULL
+ || long_memdbg_lock == NULL
+ || !CRYPTO_THREAD_init_local(&appinfokey, NULL)) {
+ CRYPTO_THREAD_lock_free(memdbg_lock);
+ memdbg_lock = NULL;
+ CRYPTO_THREAD_lock_free(long_memdbg_lock);
+ long_memdbg_lock = NULL;
return 0;
}
return 1;
static void app_info_free(APP_INFO *inf)
{
- if (!inf)
+ if (inf == NULL)
return;
if (--(inf->references) <= 0) {
app_info_free(inf->next);
if (!RUN_ONCE(&memdbg_init, do_memdbg_init))
return -1;
- CRYPTO_THREAD_write_lock(malloc_lock);
+ CRYPTO_THREAD_write_lock(memdbg_lock);
switch (mode) {
default:
break;
case CRYPTO_MEM_CHECK_DISABLE:
if (mh_mode & CRYPTO_MEM_CHECK_ON) {
CRYPTO_THREAD_ID cur = CRYPTO_THREAD_get_current_id();
- /* see if we don't have long_malloc_lock already */
+ /* see if we don't have long_memdbg_lock already */
if (!num_disable
|| !CRYPTO_THREAD_compare_id(disabling_threadid, cur)) {
/*
- * Long-time lock long_malloc_lock must not be claimed
- * while we're holding malloc_lock, or we'll deadlock
- * if somebody else holds long_malloc_lock (and cannot
+ * Long-time lock long_memdbg_lock must not be claimed
+ * while we're holding memdbg_lock, or we'll deadlock
+ * if somebody else holds long_memdbg_lock (and cannot
* release it because we block entry to this function). Give
* them a chance, first, and then claim the locks in
* appropriate order (long-time lock first).
*/
- CRYPTO_THREAD_unlock(malloc_lock);
+ CRYPTO_THREAD_unlock(memdbg_lock);
/*
- * Note that after we have waited for long_malloc_lock and
- * malloc_lock, we'll still be in the right "case" and
+ * Note that after we have waited for long_memdbg_lock and
+ * memdbg_lock, we'll still be in the right "case" and
* "if" branch because MemCheck_start and MemCheck_stop may
* never be used while there are multiple OpenSSL threads.
*/
- CRYPTO_THREAD_write_lock(long_malloc_lock);
- CRYPTO_THREAD_write_lock(malloc_lock);
+ CRYPTO_THREAD_write_lock(long_memdbg_lock);
+ CRYPTO_THREAD_write_lock(memdbg_lock);
mh_mode &= ~CRYPTO_MEM_CHECK_ENABLE;
disabling_threadid = cur;
}
num_disable--;
if (num_disable == 0) {
mh_mode |= CRYPTO_MEM_CHECK_ENABLE;
- CRYPTO_THREAD_unlock(long_malloc_lock);
+ CRYPTO_THREAD_unlock(long_memdbg_lock);
}
}
}
break;
}
- CRYPTO_THREAD_unlock(malloc_lock);
+ CRYPTO_THREAD_unlock(memdbg_lock);
return ret;
#endif
}
return 0;
cur = CRYPTO_THREAD_get_current_id();
- CRYPTO_THREAD_read_lock(malloc_lock);
+ CRYPTO_THREAD_read_lock(memdbg_lock);
ret = (mh_mode & CRYPTO_MEM_CHECK_ENABLE)
|| !CRYPTO_THREAD_compare_id(disabling_threadid, cur);
- CRYPTO_THREAD_unlock(malloc_lock);
+ CRYPTO_THREAD_unlock(memdbg_lock);
}
return ret;
}
*/
int old_mh_mode;
- CRYPTO_THREAD_write_lock(malloc_lock);
+ CRYPTO_THREAD_write_lock(memdbg_lock);
/*
* avoid deadlock when lh_free() uses CRYPTO_mem_debug_free(), which uses
mh = NULL;
mh_mode = old_mh_mode;
- CRYPTO_THREAD_unlock(malloc_lock);
+ CRYPTO_THREAD_unlock(memdbg_lock);
}
CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_OFF);
/* Clean up locks etc */
CRYPTO_THREAD_cleanup_local(&appinfokey);
- CRYPTO_THREAD_lock_free(malloc_lock);
- CRYPTO_THREAD_lock_free(long_malloc_lock);
- malloc_lock = NULL;
- long_malloc_lock = NULL;
+ CRYPTO_THREAD_lock_free(memdbg_lock);
+ CRYPTO_THREAD_lock_free(long_memdbg_lock);
+ memdbg_lock = NULL;
+ long_memdbg_lock = NULL;
return ml.chunks == 0 ? 1 : 0;
}
CRYPTO_mem_debug_push, CRYPTO_mem_debug_pop,
CRYPTO_clear_realloc, CRYPTO_clear_free,
CRYPTO_get_mem_functions, CRYPTO_set_mem_functions,
+CRYPTO_get_alloc_counts,
CRYPTO_set_mem_debug, CRYPTO_mem_ctrl,
CRYPTO_mem_leaks, CRYPTO_mem_leaks_fp, CRYPTO_mem_leaks_cb,
OPENSSL_MALLOC_FAILURES,
void *(*r)(void *, size_t, const char *, int),
void (*f)(void *, const char *, int))
+ void CRYPTO_get_alloc_counts(int *m, int *r, int *f)
+
int CRYPTO_set_mem_debug(int onoff)
env OPENSSL_MALLOC_FAILURES=... <application>
any effect, is must be called before any of the allocation functions
(e.g., CRYPTO_malloc()) are called, and is therefore normally one of the
first lines of main() in an application.
-
-If the library is built with the C<crypto-mdebug> option, then two additional
-environment variables can be used for testing failure handling. The variable
-B<OPENSSL_MALLOC_FAILURES> controls how often allocations should fail.
-It is a set of fields separated by semicolons, which each field is a count
-(defaulting to zero) and an optional atsign and percentage (defaulting
-to 100). If the count is zero, then it lasts forever. For example,
-C<100;@25> or C<100@0;0@25> means the first 100 allocations pass, then all
-other allocations (until the program exits or crashes) have a 25% chance of
-failing.
-
-If the variable B<OPENSSL_MALLOC_FD> is parsed as a positive integer, then
-it is taken as an open file descriptor, and a record of all allocations is
-written to that descriptor. If an allocation will fail, and the platform
-supports it, then a backtrace will be written to the descriptor. This can
-be useful because a malloc may fail but not be checked, and problems will
-only occur later. The following example in classic shell syntax shows how
-to use this (will not work on all platforms):
-
- OPENSSL_MALLOC_FAILURES='200;@10'
- export OPENSSL_MALLOC_FAILURES
- OPENSSL_MALLOC_FD=3
- export OPENSSL_MALLOC_FD
- ...app invocation... 3>/tmp/log$$
-
CRYPTO_mem_ctrl() provides fine-grained control of memory leak tracking.
To enable tracking call CRYPTO_mem_ctrl() with a B<mode> argument of
the B<CRYPTO_MEM_CHECK_ON>.
output string with the string, length, and userdata B<u> as the callback
parameters.
+If the library is built with the C<crypto-mdebug> option, then one
+function, CRYPTO_get_alloc_counts(), and two additional environment
+variables, B<OPENSSL_MALLOC_FAILURES> and B<OPENSSL_MALLOC_FD>,
+are available.
+
+The function CRYPTO_get_alloc_counts() fills in the number of times
+each of CRYPTO_malloc(), CRYPTO_realloc(), and CRYPTO_free() have been
+called, into the values pointed to by B<mcount>, B<rcount>, and B<fcount>,
+respectively. If a pointer is NULL, then the corresponding count is not stored.
+
+The variable
+B<OPENSSL_MALLOC_FAILURES> controls how often allocations should fail.
+It is a set of fields separated by semicolons, which each field is a count
+(defaulting to zero) and an optional atsign and percentage (defaulting
+to 100). If the count is zero, then it lasts forever. For example,
+C<100;@25> or C<100@0;0@25> means the first 100 allocations pass, then all
+other allocations (until the program exits or crashes) have a 25% chance of
+failing.
+
+If the variable B<OPENSSL_MALLOC_FD> is parsed as a positive integer, then
+it is taken as an open file descriptor, and a record of all allocations is
+written to that descriptor. If an allocation will fail, and the platform
+supports it, then a backtrace will be written to the descriptor. This can
+be useful because a malloc may fail but not be checked, and problems will
+only occur later. The following example in classic shell syntax shows how
+to use this (will not work on all platforms):
+
+ OPENSSL_MALLOC_FAILURES='200;@10'
+ export OPENSSL_MALLOC_FAILURES
+ OPENSSL_MALLOC_FD=3
+ export OPENSSL_MALLOC_FD
+ ...app invocation... 3>/tmp/log$$
+
+
=head1 RETURN VALUES
OPENSSL_malloc_init(), OPENSSL_free(), OPENSSL_clear_free()
void crypto_cleanup_all_ex_data_int(void);
int openssl_init_fork_handlers(void);
+extern CRYPTO_RWLOCK *memdbg_lock;
int openssl_strerror_r(int errnum, char *buf, size_t buflen);
# if !defined(OPENSSL_NO_STDIO)
FILE *openssl_fopen(const char *filename, const char *mode);
CRYPTO_mem_debug_pop()
int CRYPTO_mem_debug_push(const char *info, const char *file, int line);
int CRYPTO_mem_debug_pop(void);
+void CRYPTO_get_alloc_counts(int *mcount, int *rcount, int *fcount);
/*-
* Debugging functions (enabled by CRYPTO_set_mem_debug(1))
EVP_PKEY_set1_engine 4347 1_1_0g EXIST::FUNCTION:ENGINE
DH_new_by_nid 4348 1_1_1 EXIST::FUNCTION:DH
DH_get_nid 4349 1_1_1 EXIST::FUNCTION:DH
+CRYPTO_get_alloc_counts 4350 1_1_1 EXIST::FUNCTION:CRYPTO_MDEBUG