mirror of
https://github.com/Hizenberg469/Memory-Leak-Detector.git
synced 2026-04-19 17:52:26 +03:00
Implementation finished
This commit is contained in:
@@ -6,7 +6,7 @@ set(CMAKE_C_STANDARD 17)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_C_EXTENSIONS OFF)
|
||||
|
||||
set(MLD_LIB libmld)
|
||||
set(MLD_LIB mld)
|
||||
set(TEST_APP test_app)
|
||||
|
||||
set(HEADER_DIR ${CMAKE_SOURCE_DIR}/include)
|
||||
|
||||
37
app/app.c
37
app/app.c
@@ -29,7 +29,7 @@ main(int argc, char** argv) {
|
||||
|
||||
/*Step 1 : Initialize a new structure database */
|
||||
struct_db_t* struct_db = calloc(1, sizeof(struct_db_t));
|
||||
//mld_init_primitive_data_types_support(struct_db);
|
||||
mld_init_primitive_data_types_support(struct_db);
|
||||
|
||||
/*Step 2 : Create structure record for structure emp_t*/
|
||||
static field_info_t emp_fields[] = {
|
||||
@@ -57,29 +57,30 @@ main(int argc, char** argv) {
|
||||
|
||||
|
||||
|
||||
///*Working with object database*/
|
||||
///*Step 1 : Initialize a new Object database */
|
||||
//object_db_t* object_db = calloc(1, sizeof(object_db_t));
|
||||
//object_db->struct_db = struct_db;
|
||||
/*Working with object database*/
|
||||
/*Step 1 : Initialize a new Object database */
|
||||
object_db_t* object_db = calloc(1, sizeof(object_db_t));
|
||||
object_db->struct_db = struct_db;
|
||||
|
||||
///*Step 2 : Create some sample objects, equivalent to standard
|
||||
// * calloc(1, sizeof(student_t))*/
|
||||
//student_t* abhishek = xcalloc(object_db, "student_t", 1);
|
||||
//mld_set_dynamic_object_as_root(object_db, abhishek);
|
||||
/*Step 2 : Create some sample objects, equivalent to standard
|
||||
* calloc(1, sizeof(student_t))*/
|
||||
student_t* abhishek = xcalloc(object_db, "student_t", 1);
|
||||
mld_set_dynamic_object_as_root(object_db, abhishek);
|
||||
|
||||
//student_t* shivani = xcalloc(object_db, "student_t", 1);
|
||||
//strncpy(shivani->stud_name, "shivani", strlen("shivani"));
|
||||
////abhishek->best_colleage = shivani;
|
||||
student_t* shivani = xcalloc(object_db, "student_t", 1);
|
||||
strncpy(shivani->stud_name, "shivani", strlen("shivani"));
|
||||
//abhishek->best_colleage = shivani;
|
||||
|
||||
//emp_t* joseph = xcalloc(object_db, "emp_t", 2);
|
||||
emp_t* joseph = xcalloc(object_db, "emp_t", 2);
|
||||
//mld_set_dynamic_object_as_root(object_db, joseph);
|
||||
//joseph->p = xcalloc(object_db, "int", 1);
|
||||
joseph->p = xcalloc(object_db, "int", 1);
|
||||
joseph->p = NULL;
|
||||
|
||||
//print_object_db(object_db);
|
||||
print_object_db(object_db);
|
||||
|
||||
//run_mld_algorithm(object_db);
|
||||
//printf("Leaked Objects : \n");
|
||||
//report_leaked_objects(object_db);
|
||||
run_mld_algorithm(object_db);
|
||||
printf("Leaked Objects : \n");
|
||||
report_leaked_objects(object_db);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -204,6 +204,15 @@ xcalloc(object_db_t* object_db, char* struct_name, int units);
|
||||
|
||||
|
||||
|
||||
/*****API to calloc the object******/
|
||||
|
||||
|
||||
/*****API to calloc the object******/
|
||||
|
||||
void
|
||||
xfree(object_db_t* object_db, void* ptr);
|
||||
|
||||
|
||||
/*****API to calloc the object******/
|
||||
|
||||
|
||||
@@ -211,16 +220,35 @@ xcalloc(object_db_t* object_db, char* struct_name, int units);
|
||||
/*****APIs to register root objects******/
|
||||
|
||||
void
|
||||
mld_register_root_object(object_db_t* object_db,
|
||||
mld_register_global_object_as_root(object_db_t* object_db,
|
||||
void* objptr,
|
||||
char* struct_name,
|
||||
unsigned int units);
|
||||
|
||||
void
|
||||
set_mld_object_as_global_root(object_db_t* object_db, void* obj_ptr);
|
||||
mld_set_dynamic_object_as_root(object_db_t* object_db, void* obj_ptr);
|
||||
|
||||
/*****APIs to register root objects******/
|
||||
|
||||
|
||||
/*********************************************APIs' to implement MLD algorithm*************************************************/
|
||||
|
||||
void
|
||||
report_leaked_objects(object_db_t* object_db);
|
||||
|
||||
/*********************************************APIs' to implement MLD algorithm*************************************************/
|
||||
|
||||
|
||||
/********Adding support for primitive data type********/
|
||||
|
||||
void
|
||||
run_mld_algorithm(object_db_t* object_db);
|
||||
|
||||
void
|
||||
mld_init_primitive_data_types_support(struct_db_t* struct_db);
|
||||
|
||||
/********Adding support for primitive data type********/
|
||||
|
||||
/*
|
||||
* Declaration for OBJECT DATABASE
|
||||
*/
|
||||
|
||||
420
src/mld.c
420
src/mld.c
@@ -4,6 +4,7 @@
|
||||
#include "css.h"
|
||||
#include <assert.h>
|
||||
#include <memory.h>
|
||||
#include <limits.h>
|
||||
|
||||
char* DATA_TYPE[] = { "UINT8", "UINT32", "INT32",
|
||||
"CHAR", "OBJ_PTR", "VOID_PTR", "FLOAT",
|
||||
@@ -87,7 +88,7 @@ add_structure_to_struct_db(struct_db_t* struct_db, struct_db_rec_t* struct_rec)
|
||||
/******Function to lookup the structure record in structure db******/
|
||||
|
||||
/*return pointer of struct_db_rec_t on success, NULL on failure from some reason*/
|
||||
static struct_db_rec_t*
|
||||
struct_db_rec_t*
|
||||
struct_db_look_up(struct_db_t* struct_db, char* struct_name) {
|
||||
|
||||
if (!struct_db || !struct_name)
|
||||
@@ -95,6 +96,9 @@ struct_db_look_up(struct_db_t* struct_db, char* struct_name) {
|
||||
|
||||
struct_db_rec_t* struct_rec = struct_db->head;
|
||||
|
||||
if (!struct_rec)
|
||||
return NULL;
|
||||
|
||||
unsigned int sz_db = struct_db->count;
|
||||
|
||||
struct_db_rec_t* desired_rec = NULL;
|
||||
@@ -138,7 +142,7 @@ object_db_look_up(object_db_t* object_db,
|
||||
while (i < sz_db) {
|
||||
|
||||
if (head->ptr == ptr) {
|
||||
desired_obj = head->ptr;
|
||||
desired_obj = head;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -150,3 +154,415 @@ object_db_look_up(object_db_t* object_db,
|
||||
return desired_obj;
|
||||
}
|
||||
/******Function to lookup the object record in object db******/
|
||||
|
||||
|
||||
|
||||
/******Function to add object to OBJECT DB*******/
|
||||
|
||||
static void
|
||||
add_object_to_object_db(object_db_t* object_db,
|
||||
void* ptr,
|
||||
int units,
|
||||
struct_db_rec_t* struct_rec,
|
||||
mld_boolean_t is_root) {
|
||||
|
||||
object_db_rec_t* obj_rec = object_db_look_up(object_db, ptr);
|
||||
|
||||
/**Don't add some object twice**/
|
||||
assert(!obj_rec);
|
||||
|
||||
obj_rec = calloc(1, sizeof(object_db_rec_t));
|
||||
|
||||
obj_rec->next = NULL;
|
||||
obj_rec->ptr = ptr;
|
||||
obj_rec->units = units;
|
||||
obj_rec->struct_rec = struct_rec;
|
||||
obj_rec->is_visited = MLD_FALSE;
|
||||
obj_rec->is_root = is_root;
|
||||
|
||||
object_db_rec_t* head = object_db->head;
|
||||
|
||||
if (!head) {
|
||||
object_db->head = obj_rec;
|
||||
obj_rec->next = NULL;
|
||||
object_db->count++;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
obj_rec->next = head;
|
||||
object_db->head = obj_rec;
|
||||
object_db->count++;
|
||||
|
||||
}
|
||||
|
||||
void*
|
||||
xcalloc(object_db_t* object_db,
|
||||
char* struct_name,
|
||||
int units) {
|
||||
|
||||
struct_db_rec_t* struct_rec = struct_db_look_up(object_db->struct_db, struct_name);
|
||||
assert(struct_rec);
|
||||
void* ptr = calloc(units, struct_rec->ds_size);
|
||||
add_object_to_object_db(object_db, ptr, units,
|
||||
struct_rec, MLD_FALSE);
|
||||
/*xcalloc by default set the object as non-root*/
|
||||
return ptr;
|
||||
|
||||
}
|
||||
|
||||
/******Function to add object to OBJECT DB*******/
|
||||
|
||||
|
||||
|
||||
/******Function to delete object record from object db******/
|
||||
|
||||
|
||||
static void
|
||||
delete_object_record_from_object_db(object_db_t* object_db,
|
||||
object_db_rec_t* object_rec) {
|
||||
|
||||
assert(object_rec);
|
||||
|
||||
object_db_rec_t* head = object_db->head;
|
||||
if (head == object_rec) {
|
||||
object_db->head = object_rec->next;
|
||||
free(object_rec);
|
||||
return;
|
||||
}
|
||||
|
||||
object_db_rec_t* prev = head;
|
||||
head = head->next;
|
||||
|
||||
while (head) {
|
||||
if (head != object_rec) {
|
||||
prev = head;
|
||||
head = head->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
prev->next = head->next;
|
||||
head->next = NULL;
|
||||
free(head);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
xfree(object_db_t* object_db, void* ptr) {
|
||||
|
||||
if (!ptr)
|
||||
return;
|
||||
|
||||
object_db_rec_t* object_rec =
|
||||
object_db_look_up(object_db, ptr);
|
||||
|
||||
assert(object_rec);
|
||||
assert(object_rec->ptr);
|
||||
free(object_rec->ptr);
|
||||
object_rec->ptr = NULL;
|
||||
|
||||
/*Delete object record from object db*/
|
||||
delete_object_record_from_object_db(object_db, object_rec);
|
||||
|
||||
}
|
||||
|
||||
/******Function to delete object record from object db******/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/****Printing functions for dumping object db****/
|
||||
|
||||
void
|
||||
print_object_rec(object_db_rec_t* obj_rec, int i) {
|
||||
|
||||
if (!obj_rec)
|
||||
return;
|
||||
|
||||
printf(ANSI_COLOR_MAGENTA "|-------------------------------------------------------------------------------------------------------------|\n"ANSI_COLOR_RESET);
|
||||
printf(ANSI_COLOR_YELLOW "|%-3d ptr = %-10p | next = %-10p | units = %-4d | struct_name = %-10s | is_root = %s |\n"ANSI_COLOR_RESET,
|
||||
i, obj_rec->ptr, obj_rec->next, obj_rec->units, obj_rec->struct_rec->struct_name, obj_rec->is_root == MLD_TRUE? "TRUE " : "FALSE");
|
||||
printf(ANSI_COLOR_MAGENTA "|-------------------------------------------------------------------------------------------------------------|\n"ANSI_COLOR_RESET);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
print_object_db(object_db_t* object_db) {
|
||||
|
||||
|
||||
object_db_rec_t* object_rec = object_db->head;
|
||||
unsigned int i = 0;
|
||||
printf(ANSI_COLOR_CYAN "Printing OBJECT DATABASE\n" ANSI_COLOR_RESET);
|
||||
for (; object_rec; object_rec = object_rec->next) {
|
||||
print_object_rec(object_rec, i++);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/****Printing functions for dumping object db****/
|
||||
|
||||
|
||||
|
||||
/*****APIs to register root objects******/
|
||||
|
||||
/***
|
||||
|
||||
This API is used to register global object of certain as root object, which are global in scope.
|
||||
Object is not initialized by xcalloc() function.
|
||||
|
||||
***/
|
||||
|
||||
void
|
||||
mld_register_global_object_as_root(object_db_t* object_db,
|
||||
void* objptr,
|
||||
char* struct_name,
|
||||
unsigned int units) {
|
||||
|
||||
struct_db_rec_t* req_struct_rec = struct_db_look_up(object_db->struct_db, struct_name);
|
||||
|
||||
assert(req_struct_rec);
|
||||
|
||||
/*Create a new object record and add it to object database with it being a root object*/
|
||||
add_object_to_object_db(object_db, objptr, units, req_struct_rec, MLD_TRUE);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
mld_set_dynamic_object_as_root(object_db_t* object_db, void* obj_ptr) {
|
||||
|
||||
|
||||
object_db_rec_t* req_obj_rec = object_db_look_up(object_db, obj_ptr);
|
||||
|
||||
assert(req_obj_rec != NULL);
|
||||
|
||||
|
||||
req_obj_rec->is_root = MLD_TRUE;
|
||||
|
||||
}
|
||||
|
||||
/*****APIs to register root objects******/
|
||||
|
||||
|
||||
|
||||
/************************************************APIs' to implement MLD algorithm***************************************************/
|
||||
|
||||
|
||||
static object_db_rec_t*
|
||||
get_next_root_object(object_db_t* object_db, object_db_rec_t* last_root_object) {
|
||||
|
||||
object_db_rec_t* cur_obj_rec = last_root_object ? last_root_object->next : object_db->head;
|
||||
|
||||
//assert(cur_obj_rec);
|
||||
|
||||
while (cur_obj_rec) {
|
||||
|
||||
if (cur_obj_rec->is_root == MLD_TRUE)
|
||||
return cur_obj_rec;
|
||||
|
||||
cur_obj_rec = cur_obj_rec->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
init_mld_algorithm(object_db_t* object_db) {
|
||||
|
||||
object_db_rec_t* cur_obj = object_db->head;
|
||||
|
||||
while (cur_obj) {
|
||||
cur_obj->is_visited = MLD_FALSE;
|
||||
cur_obj = cur_obj->next;
|
||||
}
|
||||
}
|
||||
|
||||
//DFS algorithm to explore the Graphically oriented object set...
|
||||
static void
|
||||
mld_explore_object_recursively(object_db_t* object_db,
|
||||
object_db_rec_t* parent_obj_rec) {
|
||||
|
||||
unsigned int i, n_fields;
|
||||
char* parent_obj_ptr = NULL,
|
||||
* child_obj_offset = NULL;
|
||||
void* child_object_address = NULL;
|
||||
field_info_t* field_info = NULL;
|
||||
|
||||
object_db_rec_t* child_object_rec = NULL;
|
||||
struct_db_rec_t* parent_struct_rec = parent_obj_rec->struct_rec;
|
||||
|
||||
/*Parent object must have already visited*/
|
||||
|
||||
assert(parent_obj_rec->is_visited == MLD_TRUE);
|
||||
|
||||
if (parent_struct_rec->n_fields == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < parent_obj_rec->units; i++) {
|
||||
|
||||
parent_obj_ptr = (char*)(parent_obj_rec->ptr) + (i * parent_struct_rec->ds_size);
|
||||
|
||||
for (n_fields = 0; n_fields < parent_struct_rec->n_fields; n_fields++) {
|
||||
|
||||
field_info = &parent_struct_rec->fields[n_fields];
|
||||
|
||||
/*Only need to handle void* and obj_ptr*/
|
||||
switch (field_info->dtype) {
|
||||
case UINT8:
|
||||
case UINT32:
|
||||
case INT32:
|
||||
case CHAR:
|
||||
case FLOAT:
|
||||
case DOUBLE:
|
||||
case OBJ_STRUCT:
|
||||
break;
|
||||
case VOID_PTR:
|
||||
case OBJ_PTR:
|
||||
default:
|
||||
|
||||
|
||||
/*child_obj_offset is the memory location inside parent object
|
||||
where address of next level object is stored*/
|
||||
|
||||
child_obj_offset = parent_obj_ptr + field_info->offset;
|
||||
memcpy(&child_object_address, child_obj_offset, sizeof(void*));
|
||||
|
||||
/*child_obj_address now stores the address of the next object in the graph.
|
||||
It could be NULL, Handle that as well*/
|
||||
|
||||
if (!child_object_address)
|
||||
continue;
|
||||
|
||||
child_object_rec = object_db_look_up(object_db, child_object_address);
|
||||
|
||||
assert(child_object_rec);
|
||||
|
||||
/*Since it's a valid child object of the given parent object,
|
||||
explore it with leisure for memory leak*/
|
||||
if (child_object_rec->is_visited == MLD_FALSE) {
|
||||
child_object_rec->is_visited = MLD_TRUE;
|
||||
if (field_info->dtype != VOID_PTR)/*Explore next object only when it is not a VOID_PTR*/
|
||||
mld_explore_object_recursively(object_db, child_object_rec);
|
||||
|
||||
}
|
||||
else {
|
||||
continue; /*Do nothing, explore next child object*/
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Public API to run MLD Algorithm **/
|
||||
void
|
||||
run_mld_algorithm(object_db_t* object_db) {
|
||||
|
||||
//Necessary initialisation...
|
||||
init_mld_algorithm(object_db);
|
||||
|
||||
//Get the first root object...
|
||||
object_db_rec_t* root_obj = get_next_root_object(object_db, NULL);
|
||||
|
||||
while (root_obj) {
|
||||
if (root_obj->is_visited == MLD_TRUE) {
|
||||
//Exploration from this node object is already done...
|
||||
root_obj = get_next_root_object(object_db, root_obj);
|
||||
continue;
|
||||
}
|
||||
|
||||
root_obj->is_visited = MLD_TRUE;
|
||||
|
||||
mld_explore_object_recursively(object_db, root_obj);
|
||||
|
||||
root_obj = get_next_root_object(object_db, root_obj);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
mld_dump_object_rec_detail(object_db_rec_t* obj_rec) {
|
||||
|
||||
int n_fields = obj_rec->struct_rec->n_fields;
|
||||
|
||||
field_info_t* field = NULL;
|
||||
|
||||
int units = obj_rec->units, obj_index = 0,
|
||||
field_index = 0;
|
||||
|
||||
for (; obj_index < units; obj_index++) {
|
||||
char* current_object_ptr = (char*)(obj_rec->ptr) +
|
||||
(obj_index * obj_rec->struct_rec->ds_size);
|
||||
|
||||
for (field_index = 0; field_index < n_fields; field_index++) {
|
||||
|
||||
field = &obj_rec->struct_rec->fields[field_index];
|
||||
|
||||
switch (field->dtype) {
|
||||
case UINT8:
|
||||
case INT32:
|
||||
case UINT32:
|
||||
printf("%s[%d]->%s = %d\n", obj_rec->struct_rec->struct_name, obj_index, field->fname, *(int*)(current_object_ptr + field->offset));
|
||||
break;
|
||||
case CHAR:
|
||||
printf("%s[%d]->%s = %s\n", obj_rec->struct_rec->struct_name, obj_index, field->fname, (char*)(current_object_ptr + field->offset));
|
||||
break;
|
||||
case FLOAT:
|
||||
printf("%s[%d]->%s = %f\n", obj_rec->struct_rec->struct_name, obj_index, field->fname, *(float*)(current_object_ptr + field->offset));
|
||||
break;
|
||||
case DOUBLE:
|
||||
printf("%s[%d]->%s = %f\n", obj_rec->struct_rec->struct_name, obj_index, field->fname, *(double*)(current_object_ptr + field->offset));
|
||||
break;
|
||||
case OBJ_PTR:
|
||||
printf("%s[%d]->%s = %p\n", obj_rec->struct_rec->struct_name, obj_index, field->fname, (void*)*(int*)(current_object_ptr + field->offset));
|
||||
break;
|
||||
case OBJ_STRUCT:
|
||||
/*Later*/
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
report_leaked_objects(object_db_t* object_db) {
|
||||
|
||||
int i = 0;
|
||||
object_db_rec_t* head;
|
||||
|
||||
printf("Dumping Leaked Objects\n");
|
||||
|
||||
for (head = object_db->head; head; head = head->next) {
|
||||
if (head->is_visited == MLD_FALSE) {
|
||||
print_object_rec(head, i++);
|
||||
mld_dump_object_rec_detail(head);
|
||||
printf("\n\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/************************************************APIs' to implement MLD algorithm***************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
/********Adding support for primitive data type********/
|
||||
|
||||
void
|
||||
mld_init_primitive_data_types_support(struct_db_t* struct_db) {
|
||||
|
||||
REG_STRUCT(struct_db, int, 0);
|
||||
REG_STRUCT(struct_db, float, 0);
|
||||
REG_STRUCT(struct_db, double, 0);
|
||||
|
||||
}
|
||||
|
||||
/********Adding support for primitive data type********/
|
||||
|
||||
Reference in New Issue
Block a user