├── LICENSE ├── README.md ├── app.c ├── mld.c └── mld.h /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Debarshi Maitra 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # C-CPP-Memory-Leak-Detector 2 | 3 | This is C/C++ Memory Leak Detector Library. It maintains two databases - Structure Database and Object Database. 4 | 5 | User Application registers all its structures with MLD Library at the time of initialization. 6 | 7 | Whenever application xcalloc() an object , object record entry is inserted in object database. 8 | 9 | If there is any Memory Leak in Application Code, "report_leaked_objects()" function detects that Memory Leak. 10 | 11 | ### Compilation - 12 | 13 | gcc -g -c mld.c -o mld.o 14 | 15 | gcc -g -c app.c -o app.o 16 | 17 | gcc -g app.o mld.o -o exe 18 | 19 | For testing modify app.c file. Create some memory leaks. Do compile as mentioned above. Run the exe file. 20 | 21 | ./exe 22 | 23 | ## High Level Design 24 | 25 | ![hld](https://user-images.githubusercontent.com/47227715/138119173-d18d1baf-ca91-44f9-a1fb-bf096e4aa106.png) 26 | 27 | 28 | ## Testing MLD Library 29 | 30 | ![Screenshot (88)](https://user-images.githubusercontent.com/47227715/129093013-b998f506-de19-4222-96c8-be81e13d8393.png) 31 | 32 | ![Screenshot (89)](https://user-images.githubusercontent.com/47227715/129093018-2a518fb5-12d9-46de-b935-29afc8994097.png) 33 | 34 | ![Screenshot (90)](https://user-images.githubusercontent.com/47227715/129093029-ed8917fe-3642-4e11-9df0-106c4a1d6c40.png) 35 | 36 | ![Screenshot (85)](https://user-images.githubusercontent.com/47227715/129093080-47215fdc-713e-412d-890c-7f934dff7552.png) 37 | 38 | ![Screenshot (86)](https://user-images.githubusercontent.com/47227715/129093085-067dff81-4048-4e46-81f9-991e245f791b.png) 39 | 40 | ![Screenshot (87)](https://user-images.githubusercontent.com/47227715/129093149-3dfbb894-54a9-43cd-ab89-cad9d0dd60c9.png) 41 | -------------------------------------------------------------------------------- /app.c: -------------------------------------------------------------------------------- 1 | #include "mld.h" 2 | #include 3 | #include 4 | #include 5 | 6 | /* Application Structures */ 7 | typedef struct emp_ 8 | { 9 | char emp_name[30]; 10 | unsigned int emp_id; 11 | unsigned int age; 12 | struct emp_ *mgr; 13 | float salary; 14 | int *p; 15 | 16 | } emp_t; 17 | 18 | typedef struct student_ 19 | { 20 | char stud_name[32]; 21 | unsigned int rollno; 22 | unsigned int age; 23 | float aggregate; 24 | struct student_ *best_colleage; 25 | 26 | } student_t; 27 | 28 | 29 | int main(int argc, char **argv) 30 | { 31 | /* Step 1 : Initialize a new structure database */ 32 | struct_db_t *struct_db = calloc(1, sizeof(struct_db_t)); 33 | mld_init_primitive_data_types_support(struct_db); 34 | 35 | /* Step 2 : Create structure record for structure emp_t */ 36 | static field_info_t emp_fields[] = 37 | { 38 | FIELD_INFO(emp_t, emp_name, CHAR, 0), 39 | FIELD_INFO(emp_t, emp_id, UINT32, 0), 40 | FIELD_INFO(emp_t, age, UINT32, 0), 41 | FIELD_INFO(emp_t, mgr, OBJ_PTR, emp_t), 42 | FIELD_INFO(emp_t, salary, FLOAT, 0), 43 | FIELD_INFO(emp_t, p, OBJ_PTR, 0) 44 | }; 45 | 46 | /* Step 3 : Register the structure in structure database */ 47 | REG_STRUCT(struct_db, emp_t, emp_fields); 48 | 49 | static field_info_t stud_fiels[] = 50 | { 51 | FIELD_INFO(student_t, stud_name, CHAR, 0), 52 | FIELD_INFO(student_t, rollno, UINT32, 0), 53 | FIELD_INFO(student_t, age, UINT32, 0), 54 | FIELD_INFO(student_t, aggregate, FLOAT, 0), 55 | FIELD_INFO(student_t, best_colleage, OBJ_PTR, student_t) 56 | }; 57 | REG_STRUCT(struct_db, student_t, stud_fiels); 58 | 59 | /* Step 4 : Verify the correctness of structure database */ 60 | print_structure_db(struct_db); 61 | 62 | 63 | 64 | 65 | /* Working with object database */ 66 | 67 | /* Step 1 : Initialize a new Object database */ 68 | object_db_t *object_db = calloc(1, sizeof(object_db_t)); 69 | object_db->struct_db = struct_db; 70 | 71 | /* Step 2 : Create some sample objects, equivalent to standard calloc(1, sizeof(student_t)) */ 72 | student_t *debarshi = xcalloc(object_db, "student_t", 1); 73 | mld_set_dynamic_object_as_root(object_db, debarshi); 74 | 75 | 76 | student_t *rohit = xcalloc(object_db, "student_t", 1); 77 | strncpy(rohit->stud_name, "rohit", strlen("rohit")); 78 | 79 | //debarshi->best_colleage = rohit; 80 | 81 | 82 | emp_t *john = xcalloc(object_db, "emp_t", 2); 83 | mld_set_dynamic_object_as_root(object_db, john); 84 | john->p = xcalloc(object_db, "int", 1); 85 | john->p = NULL; 86 | 87 | 88 | print_object_db(object_db); 89 | 90 | 91 | run_mld_algorithm(object_db); 92 | 93 | 94 | printf("\n\nLeaked Objects : \n"); 95 | report_leaked_objects(object_db); 96 | 97 | return 0; 98 | } -------------------------------------------------------------------------------- /mld.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "mld.h" 4 | #include 5 | #include 6 | 7 | char *DATA_TYPE[] = {"UINT8", "UINT32", "INT32", 8 | "CHAR", "OBJ_PTR", "VOID_PTR", "FLOAT", 9 | "DOUBLE", "OBJ_STRUCT"}; 10 | 11 | /* Dumping Function */ 12 | void print_structure_rec(struct_db_rec_t *struct_rec) 13 | { 14 | if(!struct_rec) return; 15 | 16 | int j = 0; 17 | 18 | field_info_t *field = NULL; 19 | 20 | printf("|------------------------------------------------------|\n"); 21 | printf("| %-20s | size = %-8d | #flds = %-3d |\n", struct_rec->struct_name, struct_rec->ds_size, struct_rec->n_fields); 22 | printf("|------------------------------------------------------|------------------------------------------------------------------------------------------|\n"); 23 | 24 | for(j = 0 ; j < struct_rec->n_fields ; j++) 25 | { 26 | field = &struct_rec->fields[j]; 27 | 28 | printf(" %-20s |", ""); 29 | printf("%-3d %-20s | dtype = %-15s | size = %-5d | offset = %-6d| nstructname = %-20s |\n", 30 | j, field->fname, DATA_TYPE[field->dtype], field->size, field->offset, field->nested_str_name); 31 | printf(" %-20s |", ""); 32 | printf("--------------------------------------------------------------------------------------------------------------------------|\n"); 33 | } 34 | } 35 | 36 | void print_structure_db(struct_db_t *struct_db) 37 | { 38 | if(!struct_db) return; 39 | 40 | printf("Printing STRUCURE DATABASE : \n\n"); 41 | 42 | int i = 0; 43 | 44 | struct_db_rec_t *struct_rec = NULL; 45 | struct_rec = struct_db->head; 46 | 47 | printf("No of Structures Registered = %d\n\n", struct_db->count); 48 | 49 | while(struct_rec) 50 | { 51 | printf("structure No : %d (%p)\n", i++, struct_rec); 52 | print_structure_rec(struct_rec); 53 | printf("\n"); 54 | 55 | struct_rec = struct_rec->next; 56 | } 57 | } 58 | 59 | int add_structure_to_struct_db(struct_db_t *struct_db, struct_db_rec_t *struct_rec) 60 | { 61 | struct_db_rec_t *head = struct_db->head; 62 | 63 | if(!head) 64 | { 65 | struct_db->head = struct_rec; 66 | struct_rec->next = NULL; 67 | struct_db->count++; 68 | 69 | return 0; 70 | } 71 | 72 | struct_rec->next = head; 73 | struct_db->head = struct_rec; 74 | struct_db->count++; 75 | 76 | return 0; 77 | } 78 | 79 | 80 | static struct_db_rec_t *struct_db_look_up(struct_db_t *struct_db, char *struct_name) 81 | { 82 | struct_db_rec_t *head = struct_db->head; 83 | 84 | if(!head) return NULL; 85 | 86 | for(; head; head = head->next) 87 | { 88 | if(strncmp(head->struct_name, struct_name, MAX_STRUCTURE_NAME_SIZE) == 0) 89 | return head; 90 | } 91 | 92 | return NULL; 93 | } 94 | 95 | 96 | static object_db_rec_t *object_db_look_up(object_db_t *object_db, void *ptr) 97 | { 98 | object_db_rec_t *head = object_db->head; 99 | 100 | if(!head) return NULL; 101 | 102 | for(; head; head = head->next) 103 | { 104 | if(head->ptr == ptr) 105 | return head; 106 | } 107 | 108 | return NULL; 109 | } 110 | 111 | /* Working with objects */ 112 | 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) 113 | { 114 | object_db_rec_t *obj_rec = object_db_look_up(object_db, ptr); 115 | 116 | /* Dont add same object twice */ 117 | assert(!obj_rec); 118 | 119 | obj_rec = calloc(1, sizeof(object_db_rec_t)); 120 | 121 | obj_rec->next = NULL; 122 | obj_rec->ptr = ptr; 123 | obj_rec->units = units; 124 | obj_rec->struct_rec = struct_rec; 125 | obj_rec->is_visited = MLD_FALSE; 126 | obj_rec->is_root = is_root; 127 | 128 | object_db_rec_t *head = object_db->head; 129 | 130 | if(!head) 131 | { 132 | object_db->head = obj_rec; 133 | obj_rec->next = NULL; 134 | object_db->count++; 135 | 136 | return; 137 | } 138 | 139 | obj_rec->next = head; 140 | object_db->head = obj_rec; 141 | object_db->count++; 142 | } 143 | 144 | 145 | void *xcalloc(object_db_t *object_db, char *struct_name, int units) 146 | { 147 | struct_db_rec_t *struct_rec = struct_db_look_up(object_db->struct_db, struct_name); 148 | 149 | assert(struct_rec); 150 | 151 | void *ptr = calloc(units, struct_rec->ds_size); 152 | 153 | add_object_to_object_db(object_db, ptr, units, struct_rec, MLD_FALSE); /* xmalloc by default set the object as non-root */ 154 | 155 | return ptr; 156 | } 157 | 158 | 159 | static void delete_object_record_from_object_db(object_db_t *object_db, object_db_rec_t *object_rec) 160 | { 161 | assert(object_rec); 162 | 163 | object_db_rec_t *head = object_db->head; 164 | 165 | if(head == object_rec) 166 | { 167 | object_db->head = object_rec->next; 168 | 169 | free(object_rec); 170 | 171 | return; 172 | } 173 | 174 | object_db_rec_t *prev = head; 175 | head = head->next; 176 | 177 | while(head) 178 | { 179 | if(head != object_rec) 180 | { 181 | prev = head; 182 | head = head->next; 183 | 184 | continue; 185 | } 186 | 187 | prev->next = head->next; 188 | head->next = NULL; 189 | 190 | free(head); 191 | 192 | return; 193 | } 194 | } 195 | 196 | 197 | void xfree(object_db_t *object_db, void *ptr) 198 | { 199 | if(!ptr) return; 200 | 201 | object_db_rec_t *object_rec = object_db_look_up(object_db, ptr); 202 | 203 | assert(object_rec); 204 | assert(object_rec->ptr); 205 | 206 | free(object_rec->ptr); 207 | 208 | object_rec->ptr = NULL; 209 | 210 | /* Delete object record from object db */ 211 | 212 | delete_object_record_from_object_db(object_db, object_rec); 213 | } 214 | 215 | 216 | /* Dumping Functions for Object database */ 217 | void print_object_rec(object_db_rec_t *obj_rec, int i) 218 | { 219 | if(!obj_rec) return; 220 | 221 | printf("|---------------------------------------------------------------------------------------------------------------|\n"); 222 | printf("| %-3d ptr = %-10p | next = %-15p | units = %-4d | struct_name = %-10s | is_root = %s |\n", 223 | i, obj_rec->ptr, obj_rec->next, obj_rec->units, obj_rec->struct_rec->struct_name, obj_rec->is_root ? "TRUE " : "FALSE"); 224 | printf("|---------------------------------------------------------------------------------------------------------------|\n"); 225 | } 226 | 227 | void print_object_db(object_db_t *object_db) 228 | { 229 | object_db_rec_t *head = object_db->head; 230 | 231 | unsigned int i = 0; 232 | 233 | printf("Printing OBJECT DATABASE : \n\n"); 234 | 235 | for(; head ; head = head->next) 236 | { 237 | print_object_rec(head, i++); 238 | } 239 | } 240 | 241 | 242 | /* The global object of the application which is not created by xcalloc should be registered with MLD using below API */ 243 | void mld_register_global_object_as_root(object_db_t *object_db, void *objptr, char *struct_name, unsigned int units) 244 | { 245 | struct_db_rec_t *struct_rec = struct_db_look_up(object_db->struct_db, struct_name); 246 | 247 | assert(struct_rec); 248 | 249 | /* Create a new object record and add to object database */ 250 | add_object_to_object_db(object_db, objptr, units, struct_rec, MLD_TRUE); 251 | } 252 | 253 | /* Application might create an object using xcalloc , but at the same time the object 254 | can be root object. Use this API to override the object flags for the object already 255 | preent in object db */ 256 | void mld_set_dynamic_object_as_root(object_db_t *object_db, void *obj_ptr) 257 | { 258 | object_db_rec_t *obj_rec = object_db_look_up(object_db, obj_ptr); 259 | 260 | assert(obj_rec); 261 | 262 | obj_rec->is_root = MLD_TRUE; 263 | } 264 | 265 | 266 | static object_db_rec_t *get_next_root_object(object_db_t *object_db, object_db_rec_t *starting_from_here) 267 | { 268 | object_db_rec_t *first = starting_from_here ? starting_from_here->next : object_db->head; 269 | 270 | while(first) 271 | { 272 | if(first->is_root) 273 | return first; 274 | 275 | first = first->next; 276 | } 277 | 278 | return NULL; 279 | } 280 | 281 | static void init_mld_algorithm(object_db_t *object_db) 282 | { 283 | object_db_rec_t *obj_rec = object_db->head; 284 | 285 | while(obj_rec) 286 | { 287 | obj_rec->is_visited = MLD_FALSE; 288 | obj_rec = obj_rec->next; 289 | } 290 | } 291 | 292 | /* Level 2 Pseudocode : This function explore the direct childs of obj_rec and mark them visited. Note that obj_rec must have already visted. */ 293 | static void mld_explore_objects_recursively(object_db_t *object_db, object_db_rec_t *parent_obj_rec) 294 | { 295 | unsigned int i , n_fields; 296 | 297 | char *parent_obj_ptr = NULL, *child_obj_offset = NULL; 298 | void *child_object_address = NULL; 299 | field_info_t *field_info = NULL; 300 | 301 | object_db_rec_t *child_object_rec = NULL; 302 | struct_db_rec_t *parent_struct_rec = parent_obj_rec->struct_rec; 303 | 304 | /* Parent object must have already visited */ 305 | assert(parent_obj_rec->is_visited); 306 | 307 | if(parent_struct_rec->n_fields == 0) 308 | { 309 | return; 310 | } 311 | 312 | for(i = 0 ; i < parent_obj_rec->units ; i++) 313 | { 314 | parent_obj_ptr = (char *)(parent_obj_rec->ptr) + (i * parent_struct_rec->ds_size); 315 | 316 | for(n_fields = 0; n_fields < parent_struct_rec->n_fields; n_fields++) 317 | { 318 | field_info = &parent_struct_rec->fields[n_fields]; 319 | 320 | /* We are only concerned with fields which are pointer to other objects */ 321 | switch(field_info->dtype) 322 | { 323 | case UINT8: 324 | 325 | case UINT32: 326 | 327 | case INT32: 328 | 329 | case CHAR: 330 | 331 | case FLOAT: 332 | 333 | case DOUBLE: 334 | 335 | case OBJ_STRUCT: 336 | break; 337 | 338 | case VOID_PTR: 339 | 340 | case OBJ_PTR: 341 | 342 | default: 343 | ; 344 | 345 | /* child_obj_offset is the memory location inside parent object where address of next level object is stored */ 346 | child_obj_offset = parent_obj_ptr + field_info->offset; 347 | memcpy(&child_object_address, child_obj_offset, sizeof(void *)); 348 | 349 | /*child_object_address now stores the address of the next object in the graph. It could be NULL, Handle that as well*/ 350 | if(!child_object_address) continue; 351 | 352 | child_object_rec = object_db_look_up(object_db, child_object_address); 353 | 354 | assert(child_object_rec); 355 | /* Since we are able to reach this child object "child_object_rec" from parent object "parent_obj_ptr", mark this 356 | child object as visited and explore its children recirsively. 357 | If this child object is already visited, then do nothing - avoid infinite loops */ 358 | if(!child_object_rec->is_visited) 359 | { 360 | child_object_rec->is_visited = MLD_TRUE; 361 | 362 | if(field_info->dtype != VOID_PTR) /* Explore next object only when it is not a VOID_PTR */ 363 | mld_explore_objects_recursively(object_db, child_object_rec); 364 | } 365 | else 366 | { 367 | continue; /* Do nothing, explore next child object */ 368 | } 369 | } 370 | } 371 | } 372 | } 373 | 374 | /* Level 1 Pseudocode : We will traverse the graph starting from root objects and mark all reachable nodes as visited */ 375 | void run_mld_algorithm(object_db_t *object_db) 376 | { 377 | /* Step 1 : Mark all objects in object databse as unvisited */ 378 | init_mld_algorithm(object_db); 379 | 380 | /* Step 2 : Get the first root object from the object db, it could be present anywhere in object db. 381 | If there are multiple roots in object db return the first one, we can start mld algorithm from any root object */ 382 | 383 | object_db_rec_t *root_obj = get_next_root_object(object_db, NULL); 384 | 385 | while(root_obj) 386 | { 387 | if(root_obj->is_visited) 388 | { 389 | /* It means, all objects reachable from this root_obj has already been explored, no need to do it again, else you will end up in infinite loop. 390 | Remember, Application Data structures are cyclic graphs */ 391 | root_obj = get_next_root_object(object_db, root_obj); 392 | 393 | continue; 394 | } 395 | 396 | /* root objects are always reachable since application holds the global variable to it */ 397 | root_obj->is_visited = MLD_TRUE; 398 | 399 | /* Explore all reachable objects from this root_obj recursively */ 400 | mld_explore_objects_recursively(object_db, root_obj); 401 | 402 | root_obj = get_next_root_object(object_db, root_obj); 403 | } 404 | } 405 | 406 | 407 | static void mld_dump_object_rec_detail(object_db_rec_t *obj_rec) 408 | { 409 | int n_fields = obj_rec->struct_rec->n_fields; 410 | field_info_t *field = NULL; 411 | 412 | int units = obj_rec->units, obj_index = 0, field_index = 0; 413 | 414 | for(; obj_index < units ; obj_index++) 415 | { 416 | char *current_object_ptr = (char *)(obj_rec->ptr) + (obj_index * obj_rec->struct_rec->ds_size); 417 | 418 | for(field_index = 0 ; field_index < n_fields ; field_index++) 419 | { 420 | 421 | field = &obj_rec->struct_rec->fields[field_index]; 422 | 423 | switch(field->dtype) 424 | { 425 | case UINT8: 426 | 427 | case INT32: 428 | 429 | case UINT32: 430 | printf("%s[%d]->%s = %d\n", obj_rec->struct_rec->struct_name, obj_index, field->fname, *(int *)(current_object_ptr + field->offset)); 431 | break; 432 | 433 | case CHAR: 434 | printf("%s[%d]->%s = %s\n", obj_rec->struct_rec->struct_name, obj_index, field->fname, (char *)(current_object_ptr + field->offset)); 435 | break; 436 | 437 | case FLOAT: 438 | printf("%s[%d]->%s = %f\n", obj_rec->struct_rec->struct_name, obj_index, field->fname, *(float *)(current_object_ptr + field->offset)); 439 | break; 440 | 441 | case DOUBLE: 442 | printf("%s[%d]->%s = %f\n", obj_rec->struct_rec->struct_name, obj_index, field->fname, *(double *)(current_object_ptr + field->offset)); 443 | break; 444 | 445 | case OBJ_PTR: 446 | printf("%s[%d]->%s = %p\n", obj_rec->struct_rec->struct_name, obj_index, field->fname, (void *)*(long *)(current_object_ptr + field->offset)); 447 | break; 448 | 449 | case OBJ_STRUCT: 450 | /* Later */ 451 | break; 452 | 453 | default: 454 | break; 455 | } 456 | } 457 | } 458 | } 459 | 460 | 461 | void report_leaked_objects(object_db_t *object_db) 462 | { 463 | int i = 0; 464 | 465 | object_db_rec_t *head; 466 | 467 | printf("\nDumping Leaked Objects\n\n"); 468 | 469 | for(head = object_db->head ; head ; head = head->next) 470 | { 471 | if(!head->is_visited) 472 | { 473 | print_object_rec(head, i++); 474 | 475 | mld_dump_object_rec_detail(head); 476 | 477 | printf("\n\n"); 478 | } 479 | } 480 | } 481 | 482 | 483 | /* Support for primitive data types */ 484 | void mld_init_primitive_data_types_support(struct_db_t *struct_db) 485 | { 486 | REG_STRUCT(struct_db, int , 0); 487 | 488 | REG_STRUCT(struct_db, float , 0); 489 | 490 | REG_STRUCT(struct_db, double , 0); 491 | } 492 | -------------------------------------------------------------------------------- /mld.h: -------------------------------------------------------------------------------- 1 | #ifndef __MLD__ // Header Guards 2 | #define __MLD__ 3 | 4 | #include 5 | #include 6 | 7 | /*Structure Data base Definition Begin*/ 8 | #define MAX_STRUCTURE_NAME_SIZE 128 9 | #define MAX_FIELD_NAME_SIZE 128 10 | 11 | /*Enumeration for data types*/ 12 | typedef enum 13 | { 14 | UINT8, 15 | UINT32, 16 | INT32, 17 | CHAR, 18 | OBJ_PTR, 19 | VOID_PTR, /* New Data type added to identify void * pointers */ 20 | FLOAT, 21 | DOUBLE, 22 | OBJ_STRUCT 23 | 24 | } data_type_t; 25 | 26 | 27 | typedef enum 28 | { 29 | MLD_FALSE, 30 | MLD_TRUE 31 | 32 | } mld_boolean_t; 33 | 34 | 35 | 36 | #define OFFSETOF(struct_name, fld_name) (unsigned long)&(((struct_name *)0)->fld_name) 37 | 38 | #define FIELD_SIZE(struct_name, fld_name) sizeof(((struct_name *)0)->fld_name) 39 | 40 | 41 | /* Structure to store the information of one field of a C structure */ 42 | typedef struct _field_info_ 43 | { 44 | char fname [MAX_FIELD_NAME_SIZE]; /* Name of the field */ 45 | data_type_t dtype; /* Data type of the field */ 46 | unsigned int size; /* Size of the field */ 47 | unsigned int offset; /* Offset of the field */ 48 | char nested_str_name[MAX_STRUCTURE_NAME_SIZE]; /* This field is meaningful only if dtype = OBJ_PTR, Or OBJ_STRUCT */ 49 | 50 | } field_info_t; 51 | 52 | /* Structure to store the information of one C structure which could have 'n_fields' fields */ 53 | typedef struct _struct_db_rec_ 54 | { 55 | struct _struct_db_rec_ *next; /* Pointer to the next structure in the linked list */ 56 | char struct_name [MAX_STRUCTURE_NAME_SIZE]; /* Key */ 57 | unsigned int ds_size; /* Size of the structure */ 58 | unsigned int n_fields; /* No of fields in the structure */ 59 | field_info_t *fields; /* pointer to the array of fields */ 60 | 61 | } struct_db_rec_t; 62 | 63 | /*Finally the head of the linked list representing the structure database*/ 64 | typedef struct _struct_db_ 65 | { 66 | struct_db_rec_t *head; 67 | unsigned int count; 68 | 69 | } struct_db_t; 70 | 71 | /* Printing functions */ 72 | void print_structure_rec(struct_db_rec_t *struct_rec); 73 | 74 | void print_structure_db(struct_db_t *struct_db); 75 | 76 | /* Function to add the structure record in a structure database. Returns 0 on success, -1 on failure for some reason */ 77 | int add_structure_to_struct_db(struct_db_t *struct_db, struct_db_rec_t *struct_rec); 78 | 79 | 80 | #define FIELD_INFO(struct_name, fld_name, dtype, nested_struct_name) \ 81 | {#fld_name, dtype, FIELD_SIZE(struct_name, fld_name), \ 82 | OFFSETOF(struct_name, fld_name), #nested_struct_name} 83 | 84 | #define REG_STRUCT(struct_db, st_name, fields_arr) \ 85 | do \ 86 | { \ 87 | struct_db_rec_t *rec = calloc(1, sizeof(struct_db_rec_t)); \ 88 | strncpy(rec->struct_name, #st_name, MAX_STRUCTURE_NAME_SIZE); \ 89 | rec->ds_size = sizeof(st_name); \ 90 | rec->n_fields = sizeof(fields_arr) / sizeof(field_info_t); \ 91 | rec->fields = fields_arr; \ 92 | if(add_structure_to_struct_db(struct_db, rec)) \ 93 | { \ 94 | assert(0); \ 95 | } \ 96 | }while(0); 97 | 98 | 99 | 100 | 101 | /* Object Database structure definitions */ 102 | typedef struct _object_db_rec_ 103 | { 104 | struct _object_db_rec_ *next; 105 | void *ptr; 106 | unsigned int units; 107 | struct_db_rec_t *struct_rec; 108 | mld_boolean_t is_visited; /* Used for Graph traversal */ 109 | mld_boolean_t is_root; /* Is this object is Root object */ 110 | } object_db_rec_t;; 111 | 112 | typedef struct _object_db_ 113 | { 114 | struct_db_t *struct_db; 115 | object_db_rec_t *head; 116 | unsigned int count; 117 | 118 | } object_db_t; 119 | 120 | 121 | /* Dumping functions */ 122 | void print_object_rec(object_db_rec_t *obj_rec, int i); 123 | 124 | void print_object_db(object_db_t *object_db); 125 | 126 | /* API to malloc the object */ 127 | void* xcalloc(object_db_t *object_db, char *struct_name, int units); 128 | 129 | /* APIs to register root objects */ 130 | void mld_register_root_object (object_db_t *object_db, void *objptr, char *struct_name, unsigned int units); 131 | 132 | void set_mld_object_as_global_root(object_db_t *object_db, void *obj_ptr); 133 | 134 | 135 | /* APIs for MLD Algorithm */ 136 | void run_mld_algorithm(object_db_t *object_db); 137 | 138 | void report_leaked_objects(object_db_t *object_db); 139 | 140 | void mld_set_dynamic_object_as_root(object_db_t *object_db, void *obj_ptr); 141 | 142 | void mld_init_primitive_data_types_support(struct_db_t *struct_db); 143 | 144 | #endif 145 | --------------------------------------------------------------------------------