be_pair: release shared lock with the latest of bufferevent_pair Then next code sample will use free'd lock: evthread_use_pthreads(); ... assert(!bufferevent_pair_new(base, BEV_OPT_THREADSAFE, pair)); ... bufferevent_free(pair[0]); # refcnt == 0 -> unlink bufferevent_free(pair[1]); # refcnt == 0 -> unlink ... event_base_free() -> finalizers -> EVTHREAD_FREE_LOCK(bev1->lock) -> BEV_LOCK(bev2->lock) <-- *already freed* While if you will reverse the order: bufferevent_free(pair[1]); # refcnt == 0 -> unlink bufferevent_free(pair[0]); # refcnt == 0 -> unlink ... event_base_free() -> finalizers -> BEV_LOCK(bev2->lock)/!own_lock/BEV_UNLOCK(bev2->lock) -> EVTHREAD_FREE_LOCK(bev1->lock) (own_lock) It is ok now, but I guess that it will be better to relax order of freeing pairs.