static void int_thread_del_item(const ERR_STATE *d) { ERR_STATE *p; LHASH *hash; err_fns_check(); hash = ERRFN(thread_get)(0); if (!hash) return; CRYPTO_w_lock(CRYPTO_LOCK_ERR); p = (ERR_STATE *)lh_delete(hash, d); /* make sure we don't leak memory */ if (int_thread_hash_references == 1 && int_thread_hash && (lh_num_items(int_thread_hash) == 0)) { lh_free(int_thread_hash); int_thread_hash = NULL; } CRYPTO_w_unlock(CRYPTO_LOCK_ERR); ERRFN(thread_release)(&hash); if (p) ERR_STATE_free(p); }
void OBJ_NAME_do_all_sorted(int type,void (*fn)(const OBJ_NAME *,void *arg), void *arg) { struct doall_sorted d; int n; d.type=type; d.names=OPENSSL_malloc(lh_num_items(names_lh)*sizeof *d.names); d.n=0; OBJ_NAME_do_all(type,do_all_sorted_fn,&d); qsort((void *)d.names,d.n,sizeof *d.names,do_all_sorted_cmp); for(n=0 ; n < d.n ; ++n) fn(d.names[n],arg); OPENSSL_free((void *)d.names); }
void ERR_remove_state(unsigned long pid) { ERR_STATE *p = NULL,tmp; if (thread_hash == NULL) return; if (pid == 0) pid=(unsigned long)CRYPTO_thread_id(); tmp.pid=pid; CRYPTO_w_lock(CRYPTO_LOCK_ERR); if (thread_hash) { p=(ERR_STATE *)lh_delete(thread_hash,&tmp); if (lh_num_items(thread_hash) == 0) { /* make sure we don't leak memory */ lh_free(thread_hash); thread_hash = NULL; } } CRYPTO_w_unlock(CRYPTO_LOCK_ERR); if (p != NULL) ERR_STATE_free(p); }
void CRYPTO_mem_leaks(BIO *b) { MEM_LEAK ml; if (mh == NULL && amih == NULL) return; MemCheck_off(); /* obtain MALLOC2 lock */ ml.bio=b; ml.bytes=0; ml.chunks=0; if (mh != NULL) lh_doall_arg(mh, LHASH_DOALL_ARG_FN(print_leak), (char *)&ml); if (ml.chunks != 0) { BIO_printf(b,"%ld bytes leaked in %d chunks\n", ml.bytes,ml.chunks); } else { /* Make sure that, if we found no leaks, memory-leak debugging itself * does not introduce memory leaks (which might irritate * external debugging tools). * (When someone enables leak checking, but does not call * this function, we declare it to be their fault.) * * XXX This should be in CRYPTO_mem_leaks_cb, * and CRYPTO_mem_leaks should be implemented by * using CRYPTO_mem_leaks_cb. * (Also their should be a variant of lh_doall_arg * that takes a function pointer instead of a void *; * this would obviate the ugly and illegal * void_fn_to_char kludge in CRYPTO_mem_leaks_cb. * Otherwise the code police will come and get us.) */ int old_mh_mode; CRYPTO_w_lock(CRYPTO_LOCK_MALLOC); /* avoid deadlock when lh_free() uses CRYPTO_dbg_free(), * which uses CRYPTO_is_mem_check_on */ old_mh_mode = mh_mode; mh_mode = CRYPTO_MEM_CHECK_OFF; if (mh != NULL) { lh_free(mh); mh = NULL; } if (amih != NULL) { if (lh_num_items(amih) == 0) { lh_free(amih); amih = NULL; } } mh_mode = old_mh_mode; CRYPTO_w_unlock(CRYPTO_LOCK_MALLOC); } MemCheck_on(); /* release MALLOC2 lock */ }
int main(int argc, char **argv) { _LHASH *lh; struct dummy_lhash dummy_lh = {NULL}; unsigned i; CRYPTO_library_init(); lh = lh_new(NULL, NULL); if (lh == NULL) { return 1; } for (i = 0; i < 100000; i++) { unsigned action; char *s, *s1, *s2; if (dummy_lh_num_items(&dummy_lh) != lh_num_items(lh)) { fprintf(stderr, "Length mismatch\n"); return 1; } action = rand() % 3; switch (action) { case 0: s = rand_string(); s1 = (char *)lh_retrieve(lh, s); s2 = dummy_lh_retrieve(&dummy_lh, s); if (s1 != NULL && (s2 == NULL || strcmp(s1, s2) != 0)) { fprintf(stderr, "lh_retrieve failure\n"); abort(); } free(s); break; case 1: s = rand_string(); lh_insert(lh, (void **)&s1, s); dummy_lh_insert(&dummy_lh, &s2, strdup(s)); if (s1 != NULL && (s2 == NULL || strcmp(s1, s2) != 0)) { fprintf(stderr, "lh_insert failure\n"); abort(); } if (s1) { free(s1); } if (s2) { free(s2); } break; case 2: s = rand_string(); s1 = lh_delete(lh, s); s2 = dummy_lh_delete(&dummy_lh, s); if (s1 != NULL && (s2 == NULL || strcmp(s1, s2) != 0)) { fprintf(stderr, "lh_insert failure\n"); abort(); } if (s1) { free(s1); } if (s2) { free(s2); } free(s); break; default: abort(); } } lh_doall(lh, free); lh_free(lh); dummy_lh_free(&dummy_lh); printf("PASS\n"); return 0; }