Commit e1954482 authored by Simon Morlat's avatar Simon Morlat
Browse files

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 ...@@ -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); 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); 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) { ...@@ -40,8 +40,45 @@ void belle_sip_object_enable_marshal_check(int enable) {
_belle_sip_object_marshal_check_enabled = (enable) ? TRUE : FALSE; _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 * _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); belle_sip_object_t *obj=(belle_sip_object_t *)belle_sip_malloc0(objsize);
obj->ref=vptr->initially_unowned ? 0 : 1; obj->ref=vptr->initially_unowned ? 0 : 1;
obj->vptr=vptr; obj->vptr=vptr;
obj->size=objsize; obj->size=objsize;
...@@ -49,6 +86,7 @@ belle_sip_object_t * _belle_sip_object_new(size_t objsize, belle_sip_object_vptr ...@@ -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(); belle_sip_object_pool_t *pool=belle_sip_object_pool_get_current();
if (pool) belle_sip_object_pool_add(pool,obj); if (pool) belle_sip_object_pool_add(pool,obj);
} }
add_new_object(obj);
return obj; return obj;
} }
...@@ -171,6 +209,7 @@ void belle_sip_object_delete(void *ptr){ ...@@ -171,6 +209,7 @@ void belle_sip_object_delete(void *ptr){
belle_sip_object_vptr_t *vptr; belle_sip_object_vptr_t *vptr;
belle_sip_object_loose_weak_refs(obj); belle_sip_object_loose_weak_refs(obj);
remove_free_object(obj);
vptr=obj->vptr; vptr=obj->vptr;
while(vptr!=NULL){ while(vptr!=NULL){
if (vptr->destroy) vptr->destroy(obj); if (vptr->destroy) vptr->destroy(obj);
...@@ -221,6 +260,7 @@ belle_sip_object_t *belle_sip_object_clone(const belle_sip_object_t *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(); belle_sip_object_pool_t *pool=belle_sip_object_pool_get_current();
if (pool) belle_sip_object_pool_add(pool,newobj); if (pool) belle_sip_object_pool_add(pool,newobj);
} }
add_new_object(newobj);
return newobj; return newobj;
} }
...@@ -748,4 +788,3 @@ belle_sip_object_pool_t *belle_sip_object_pool_get_current(void){ ...@@ -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 ...@@ -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 a non-2xx final response, any early dialogs created through
provisional responses to that request are terminated. The mechanism provisional responses to that request are terminated. The mechanism
for terminating confirmed dialogs is method specific.*/ for terminating confirmed dialogs is method specific.*/
belle_sip_dialog_delete(obj); delete_dialog=TRUE;
break; break;
} }
if (code>=200 && code<300 && (strcmp(belle_sip_request_get_method(req),"INVITE")==0 || strcmp(belle_sip_request_get_method(req),"SUBSCRIBE")==0)) 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 ...@@ -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); belle_sip_message_add_headers((belle_sip_message_t*)ack,aut);
if (prx_aut) if (prx_aut)
belle_sip_message_add_headers((belle_sip_message_t*)ack,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; return ack;
} }
...@@ -653,7 +655,7 @@ belle_sip_request_t *belle_sip_dialog_create_queued_request_from(belle_sip_dialo ...@@ -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){ void belle_sip_dialog_delete(belle_sip_dialog_t *obj){
int dropped_transactions; int dropped_transactions;
belle_sip_message("dialog [%p] deleted.",obj);
belle_sip_dialog_stop_200Ok_retrans(obj); /*if any*/ belle_sip_dialog_stop_200Ok_retrans(obj); /*if any*/
set_state(obj,BELLE_SIP_DIALOG_TERMINATED); set_state(obj,BELLE_SIP_DIALOG_TERMINATED);
dropped_transactions=belle_sip_list_size(obj->queued_ct); dropped_transactions=belle_sip_list_size(obj->queued_ct);
......
...@@ -356,20 +356,13 @@ BELLE_SIP_PARSE(request) ...@@ -356,20 +356,13 @@ BELLE_SIP_PARSE(request)
GET_SET_STRING(belle_sip_request,method); GET_SET_STRING(belle_sip_request,method);
GET_SET_STRING(belle_sip_request,rfc2543_branch); 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){ void belle_sip_request_set_dialog(belle_sip_request_t *req, belle_sip_dialog_t *dialog){
if (dialog) belle_sip_object_ref(dialog); SET_OBJECT_PROPERTY(req,dialog,dialog);
if (req->dialog) {
belle_sip_object_unref(req->dialog);
}
req->dialog=dialog;
} }
void belle_sip_request_set_uri(belle_sip_request_t* request,belle_sip_uri_t* uri) { void belle_sip_request_set_uri(belle_sip_request_t* request,belle_sip_uri_t* uri) {
belle_sip_object_ref(uri); SET_OBJECT_PROPERTY(request,uri,uri);
if (request->uri) {
belle_sip_object_unref(request->uri);
}
request->uri=uri;
} }
belle_sip_uri_t * belle_sip_request_get_uri(const belle_sip_request_t *request){ 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) { ...@@ -55,11 +55,26 @@ static void belle_sip_authorization_destroy(authorization_context_t* object) {
belle_sip_free(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){ 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->listeners=belle_sip_list_free(p->listeners);
p->internal_listeners=belle_sip_list_free(p->internal_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->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->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); 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