Commit e1954482 authored by Simon Morlat's avatar Simon Morlat

fix memory leak. Add object leak detector builtin.

parent 19353b93
......@@ -170,6 +170,20 @@ BELLESIP_EXPORT belle_sip_object_t * _belle_sip_object_new(size_t objsize, belle
**/
BELLESIP_EXPORT void belle_sip_object_enable_marshal_check(int enable);
/**
* Activates an object leak detector. When enabled, belle-sip will reference all created objects.
* At program termination, application can check if objects remain alive using belle_sip_object_get_object_count() and dump them with
* belle_sip_object_dump_active_objects().
* @warning this must not be used in multi-threaded programs (when multiple threads can access belle-sip at the same time)
* Useful for debug purposes.
* @param enable TRUE to enable, FALSE to disable.
**/
BELLESIP_EXPORT void belle_sip_object_enable_leak_detector(int enable);
BELLESIP_EXPORT int belle_sip_object_get_object_count(void);
BELLESIP_EXPORT void belle_sip_object_dump_active_objects(void);
int belle_sip_object_is_unowed(const belle_sip_object_t *obj);
/**
......
......@@ -40,8 +40,45 @@ void belle_sip_object_enable_marshal_check(int enable) {
_belle_sip_object_marshal_check_enabled = (enable) ? TRUE : FALSE;
}
static belle_sip_list_t *all_objects=NULL;
static int belle_sip_leak_detector_enabled=FALSE;
static void add_new_object(belle_sip_object_t *obj){
if (belle_sip_leak_detector_enabled){
all_objects=belle_sip_list_prepend(all_objects,obj);
}
}
static void remove_free_object(belle_sip_object_t *obj){
if (belle_sip_leak_detector_enabled){
all_objects=belle_sip_list_remove(all_objects,obj);
}
}
void belle_sip_object_enable_leak_detector(int enable){
belle_sip_leak_detector_enabled=enable;
}
int belle_sip_object_get_object_count(void){
return belle_sip_list_size(all_objects);
}
void belle_sip_object_dump_active_objects(void){
belle_sip_list_t *elem;
if (all_objects){
belle_sip_message("List of leaked objects:");
for(elem=all_objects;elem!=NULL;elem=elem->next){
belle_sip_object_t *obj=(belle_sip_object_t*)elem->data;
belle_sip_message("%s(%p) ref=%i",obj->vptr->type_name,obj,obj->ref);
}
}else belle_sip_message("No objects leaked.");
}
belle_sip_object_t * _belle_sip_object_new(size_t objsize, belle_sip_object_vptr_t *vptr){
belle_sip_object_t *obj=(belle_sip_object_t *)belle_sip_malloc0(objsize);
obj->ref=vptr->initially_unowned ? 0 : 1;
obj->vptr=vptr;
obj->size=objsize;
......@@ -49,6 +86,7 @@ belle_sip_object_t * _belle_sip_object_new(size_t objsize, belle_sip_object_vptr
belle_sip_object_pool_t *pool=belle_sip_object_pool_get_current();
if (pool) belle_sip_object_pool_add(pool,obj);
}
add_new_object(obj);
return obj;
}
......@@ -171,6 +209,7 @@ void belle_sip_object_delete(void *ptr){
belle_sip_object_vptr_t *vptr;
belle_sip_object_loose_weak_refs(obj);
remove_free_object(obj);
vptr=obj->vptr;
while(vptr!=NULL){
if (vptr->destroy) vptr->destroy(obj);
......@@ -221,6 +260,7 @@ belle_sip_object_t *belle_sip_object_clone(const belle_sip_object_t *obj){
belle_sip_object_pool_t *pool=belle_sip_object_pool_get_current();
if (pool) belle_sip_object_pool_add(pool,newobj);
}
add_new_object(newobj);
return newobj;
}
......@@ -748,4 +788,3 @@ belle_sip_object_pool_t *belle_sip_object_pool_get_current(void){
}
......@@ -370,7 +370,7 @@ int belle_sip_dialog_update(belle_sip_dialog_t *obj, belle_sip_transaction_t* tr
a non-2xx final response, any early dialogs created through
provisional responses to that request are terminated. The mechanism
for terminating confirmed dialogs is method specific.*/
belle_sip_dialog_delete(obj);
delete_dialog=TRUE;
break;
}
if (code>=200 && code<300 && (strcmp(belle_sip_request_get_method(req),"INVITE")==0 || strcmp(belle_sip_request_get_method(req),"SUBSCRIBE")==0))
......@@ -526,6 +526,8 @@ belle_sip_request_t *belle_sip_dialog_create_ack(belle_sip_dialog_t *obj, unsign
belle_sip_message_add_headers((belle_sip_message_t*)ack,aut);
if (prx_aut)
belle_sip_message_add_headers((belle_sip_message_t*)ack,prx_aut);
/*the ack is sent statelessly, the transaction layer doesn't need the dialog information*/
belle_sip_request_set_dialog(ack,NULL);
}
return ack;
}
......@@ -653,7 +655,7 @@ belle_sip_request_t *belle_sip_dialog_create_queued_request_from(belle_sip_dialo
void belle_sip_dialog_delete(belle_sip_dialog_t *obj){
int dropped_transactions;
belle_sip_message("dialog [%p] deleted.",obj);
belle_sip_dialog_stop_200Ok_retrans(obj); /*if any*/
set_state(obj,BELLE_SIP_DIALOG_TERMINATED);
dropped_transactions=belle_sip_list_size(obj->queued_ct);
......
......@@ -356,20 +356,13 @@ BELLE_SIP_PARSE(request)
GET_SET_STRING(belle_sip_request,method);
GET_SET_STRING(belle_sip_request,rfc2543_branch);
/*caching of the dialog in the request, used when creating a request in dialog to avoid dialog lookup*/
void belle_sip_request_set_dialog(belle_sip_request_t *req, belle_sip_dialog_t *dialog){
if (dialog) belle_sip_object_ref(dialog);
if (req->dialog) {
belle_sip_object_unref(req->dialog);
}
req->dialog=dialog;
SET_OBJECT_PROPERTY(req,dialog,dialog);
}
void belle_sip_request_set_uri(belle_sip_request_t* request,belle_sip_uri_t* uri) {
belle_sip_object_ref(uri);
if (request->uri) {
belle_sip_object_unref(request->uri);
}
request->uri=uri;
SET_OBJECT_PROPERTY(request,uri,uri);
}
belle_sip_uri_t * belle_sip_request_get_uri(const belle_sip_request_t *request){
......
......@@ -55,11 +55,26 @@ static void belle_sip_authorization_destroy(authorization_context_t* object) {
belle_sip_free(object);
}
static void finalize_transaction(belle_sip_transaction_t *tr){
belle_sip_transaction_state_t state=belle_sip_transaction_get_state(tr);
if (state!=BELLE_SIP_TRANSACTION_TERMINATED){
belle_sip_message("Transaction [%p] still in state [%s], will force termination.",tr,belle_sip_transaction_state_to_string(state));
belle_sip_transaction_terminate(tr);
}
}
static void finalize_transactions(const belle_sip_list_t *l){
belle_sip_list_t *copy=belle_sip_list_copy(l);
belle_sip_list_free_with_data(copy,(void (*)(void*))finalize_transaction);
}
static void belle_sip_provider_uninit(belle_sip_provider_t *p){
finalize_transactions(p->client_transactions);
p->client_transactions=NULL;
finalize_transactions(p->server_transactions);
p->server_transactions=NULL;
p->listeners=belle_sip_list_free(p->listeners);
p->internal_listeners=belle_sip_list_free(p->internal_listeners);
p->client_transactions=belle_sip_list_free_with_data(p->client_transactions,belle_sip_object_unref);
p->server_transactions=belle_sip_list_free_with_data(p->server_transactions,belle_sip_object_unref);
p->auth_contexts=belle_sip_list_free_with_data(p->auth_contexts,(void(*)(void*))belle_sip_authorization_destroy);
p->dialogs=belle_sip_list_free_with_data(p->dialogs,belle_sip_object_unref);
p->lps=belle_sip_list_free_with_data(p->lps,belle_sip_object_unref);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment