mirror of
https://github.com/Hizenberg469/Memory-Leak-Detector.git
synced 2026-04-19 17:52:26 +03:00
Phase 1 and Phase2 implemented
This commit is contained in:
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
*vsidx
|
||||||
|
*.opendb
|
||||||
|
.vs
|
||||||
|
out
|
||||||
|
CMakePresets.json
|
||||||
16
CMakeLists.txt
Normal file
16
CMakeLists.txt
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.22.1)
|
||||||
|
|
||||||
|
project(Memory-Leak-Detector VERSION 1.0.0 LANGUAGES C CXX)
|
||||||
|
|
||||||
|
set(CMAKE_C_STANDARD 17)
|
||||||
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_C_EXTENSIONS OFF)
|
||||||
|
|
||||||
|
set(MLD_LIB libmld)
|
||||||
|
set(TEST_APP test_app)
|
||||||
|
|
||||||
|
set(HEADER_DIR ${CMAKE_SOURCE_DIR}/include)
|
||||||
|
set(SOURCE_DIR ${CMAKE_SOURCE_DIR}/src)
|
||||||
|
|
||||||
|
add_subdirectory(src)
|
||||||
|
add_subdirectory(app)
|
||||||
10
app/CMakeLists.txt
Normal file
10
app/CMakeLists.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
set(TESTING_APP "app.c")
|
||||||
|
|
||||||
|
add_executable(${TEST_APP}
|
||||||
|
${TESTING_APP})
|
||||||
|
|
||||||
|
target_include_directories(${TEST_APP} PUBLIC
|
||||||
|
${HEADER_DIR})
|
||||||
|
|
||||||
|
target_link_libraries(${TEST_APP} PUBLIC
|
||||||
|
${MLD_LIB})
|
||||||
85
app/app.c
Normal file
85
app/app.c
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
#include "mld.h"
|
||||||
|
#include <memory.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/*Application Structures*/
|
||||||
|
|
||||||
|
typedef struct emp_ {
|
||||||
|
|
||||||
|
char emp_name[30];
|
||||||
|
unsigned int emp_id;
|
||||||
|
unsigned int age;
|
||||||
|
struct emp_* mgr;
|
||||||
|
float salary;
|
||||||
|
int* p;
|
||||||
|
} emp_t;
|
||||||
|
|
||||||
|
typedef struct student_ {
|
||||||
|
|
||||||
|
char stud_name[32];
|
||||||
|
unsigned int rollno;
|
||||||
|
unsigned int age;
|
||||||
|
float aggregate;
|
||||||
|
struct student_* best_colleage;
|
||||||
|
} student_t;
|
||||||
|
|
||||||
|
int
|
||||||
|
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);
|
||||||
|
|
||||||
|
/*Step 2 : Create structure record for structure emp_t*/
|
||||||
|
static field_info_t emp_fields[] = {
|
||||||
|
FIELD_INFO(emp_t, emp_name, CHAR, 0),
|
||||||
|
FIELD_INFO(emp_t, emp_id, UINT32, 0),
|
||||||
|
FIELD_INFO(emp_t, age, UINT32, 0),
|
||||||
|
FIELD_INFO(emp_t, mgr, OBJ_PTR, emp_t),
|
||||||
|
FIELD_INFO(emp_t, salary, FLOAT, 0),
|
||||||
|
FIELD_INFO(emp_t, p, OBJ_PTR, 0)
|
||||||
|
};
|
||||||
|
/*Step 3 : Register the structure in structure database*/
|
||||||
|
REG_STRUCT(struct_db, emp_t, emp_fields);
|
||||||
|
|
||||||
|
static field_info_t stud_fiels[] = {
|
||||||
|
FIELD_INFO(student_t, stud_name, CHAR, 0),
|
||||||
|
FIELD_INFO(student_t, rollno, UINT32, 0),
|
||||||
|
FIELD_INFO(student_t, age, UINT32, 0),
|
||||||
|
FIELD_INFO(student_t, aggregate, FLOAT, 0),
|
||||||
|
FIELD_INFO(student_t, best_colleage, OBJ_PTR, student_t)
|
||||||
|
};
|
||||||
|
REG_STRUCT(struct_db, student_t, stud_fiels);
|
||||||
|
|
||||||
|
/*Step 4 : Verify the correctness of structure database*/
|
||||||
|
print_structure_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);
|
||||||
|
|
||||||
|
//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);
|
||||||
|
//mld_set_dynamic_object_as_root(object_db, joseph);
|
||||||
|
//joseph->p = xcalloc(object_db, "int", 1);
|
||||||
|
|
||||||
|
//print_object_db(object_db);
|
||||||
|
|
||||||
|
//run_mld_algorithm(object_db);
|
||||||
|
//printf("Leaked Objects : \n");
|
||||||
|
//report_leaked_objects(object_db);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
12
include/css.h
Normal file
12
include/css.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#ifndef __CSS__
|
||||||
|
#define __CSS__
|
||||||
|
|
||||||
|
#define ANSI_COLOR_RED "\x1b[31m"
|
||||||
|
#define ANSI_COLOR_GREEN "\x1b[32m"
|
||||||
|
#define ANSI_COLOR_YELLOW "\x1b[33m"
|
||||||
|
#define ANSI_COLOR_BLUE "\x1b[34m"
|
||||||
|
#define ANSI_COLOR_MAGENTA "\x1b[35m"
|
||||||
|
#define ANSI_COLOR_CYAN "\x1b[36m"
|
||||||
|
#define ANSI_COLOR_RESET "\x1b[0m"
|
||||||
|
|
||||||
|
#endif
|
||||||
233
include/mld.h
Normal file
233
include/mld.h
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
#ifndef __MLD__
|
||||||
|
#define __MLD__
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Declaration for STRUCTURE DATABASE
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __STRUCT_DB__
|
||||||
|
#define __STRUCT_DB__
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define MAX_STRUCTURE_NAME_SIZE 128
|
||||||
|
#define MAX_FIELD_NAME_SIZE 128
|
||||||
|
|
||||||
|
/**Enumeration for data types**/
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
|
||||||
|
UINT8,
|
||||||
|
UINT32,
|
||||||
|
INT32,
|
||||||
|
CHAR,
|
||||||
|
OBJ_PTR,
|
||||||
|
VOID_PTR, /* To identify void-pointer type */
|
||||||
|
FLOAT,
|
||||||
|
DOUBLE,
|
||||||
|
OBJ_STRUCT
|
||||||
|
|
||||||
|
}data_type_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
|
||||||
|
MLD_FALSE,
|
||||||
|
MLD_TRUE
|
||||||
|
|
||||||
|
} mld_boolean_t;
|
||||||
|
|
||||||
|
/**Enumeration for data types**/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define FIELD_OFFSET( struct_name, field_name ) \
|
||||||
|
(unsigned int)&(((struct_name* )0)->field_name)
|
||||||
|
|
||||||
|
#define FIELD_SIZE( struct_name, field_name ) \
|
||||||
|
sizeof(((struct_name* )0)->field_name)
|
||||||
|
|
||||||
|
|
||||||
|
/******Struture to store the information of one field of a C structure******/
|
||||||
|
|
||||||
|
typedef struct _field_info_ {
|
||||||
|
|
||||||
|
char fname[MAX_FIELD_NAME_SIZE]; //Name of the field
|
||||||
|
data_type_t dtype; //Data type registered
|
||||||
|
unsigned int size; //Size of the field
|
||||||
|
unsigned int offset; //Offset of field in the structure object
|
||||||
|
|
||||||
|
// Below field is meaningful only if dtype = OBJ_PTR, Or OBJ_STRUCT
|
||||||
|
|
||||||
|
char nested_str_name[MAX_STRUCTURE_NAME_SIZE];
|
||||||
|
}field_info_t;
|
||||||
|
|
||||||
|
/******Struture to store the information of one field of a C structure******/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/******Structure to store the information of one C structure which could have 'n_fields' fields******/
|
||||||
|
|
||||||
|
typedef struct _struct_db_rec_ {
|
||||||
|
|
||||||
|
struct _struct_db_rec_* next; //Pointer to next structure in db
|
||||||
|
char struct_name[MAX_STRUCTURE_NAME_SIZE]; //Name of Structure variable
|
||||||
|
unsigned int ds_size; //Size of structure object
|
||||||
|
unsigned int n_fields; //No. of fields in this structure
|
||||||
|
field_info_t* fields; //Pointer to array of fields
|
||||||
|
|
||||||
|
} struct_db_rec_t;
|
||||||
|
|
||||||
|
/******Structure to store the information of one C structure which could have 'n_fields' fields******/
|
||||||
|
|
||||||
|
|
||||||
|
/*****Structure Data base Definition******/
|
||||||
|
|
||||||
|
typedef struct _struct_db_ {
|
||||||
|
|
||||||
|
struct_db_rec_t* head; //Head of the Database
|
||||||
|
unsigned int count; //No. of records in Database
|
||||||
|
|
||||||
|
} struct_db_t;
|
||||||
|
|
||||||
|
/*****Structure Data base Definition******/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**********Printing functions**********/
|
||||||
|
|
||||||
|
void
|
||||||
|
print_structure_rec(struct_db_rec_t* struct_rec);
|
||||||
|
|
||||||
|
void
|
||||||
|
print_structure_db(struct_db_t* struct_db);
|
||||||
|
|
||||||
|
/**********Printing functions**********/
|
||||||
|
|
||||||
|
|
||||||
|
/******Function to add the structure record to structure db******/
|
||||||
|
|
||||||
|
/*return 0 on success, -1 on failure from some reason*/
|
||||||
|
int
|
||||||
|
add_structure_to_struct_db(struct_db_t* struct_db, struct_db_rec_t* struct_rec);
|
||||||
|
|
||||||
|
/******Function to add the structure record to structure db******/
|
||||||
|
|
||||||
|
/******Function to lookup the structure record in structure db******/
|
||||||
|
|
||||||
|
/*return pointer of struct_db_rec_t on success, NULL on failure from some reason*/
|
||||||
|
struct_db_rec_t*
|
||||||
|
struct_db_look_up(struct_db_t* struct_db, char* struct_name);
|
||||||
|
|
||||||
|
/******Function to lookup the structure record in structure db******/
|
||||||
|
|
||||||
|
|
||||||
|
/*********Structure Registration helpint API***********/
|
||||||
|
|
||||||
|
/**#fld_name is used to convert the fld_name to string "fld_name" if used in #define preprocessor**/
|
||||||
|
|
||||||
|
#define FIELD_INFO( struct_name, fld_name, dtype, nested_struct_name ) \
|
||||||
|
{#fld_name, dtype, FIELD_SIZE(struct_name, fld_name), \
|
||||||
|
FIELD_OFFSET(struct_name, fld_name), #nested_struct_name }
|
||||||
|
|
||||||
|
#define REG_STRUCT(struct_db, st_name, fields_arr) \
|
||||||
|
do{ \
|
||||||
|
struct_db_rec_t* rec = calloc(1, sizeof(struct_db_rec_t)); \
|
||||||
|
rec->next = NULL; \
|
||||||
|
strncpy(rec->struct_name, #st_name, MAX_STRUCTURE_NAME_SIZE); \
|
||||||
|
rec->ds_size = sizeof(st_name); \
|
||||||
|
rec->n_fields = sizeof(fields_arr)/sizeof(field_info_t); \
|
||||||
|
rec->fields = fields_arr; \
|
||||||
|
if( add_structure_to_struct_db(struct_db, rec)){ \
|
||||||
|
assert(0); \
|
||||||
|
} \
|
||||||
|
}while(0);
|
||||||
|
|
||||||
|
|
||||||
|
/*********Structure Registration helpint API***********/
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Declaration for STRUCTURE DATABASE
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __OBJECT_DB__
|
||||||
|
#define __OJBECT_DB__
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Declaration for OBJECT DATABASE
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct _object_db_rec_ object_db_rec_t;
|
||||||
|
|
||||||
|
struct _object_db_rec_ {
|
||||||
|
|
||||||
|
object_db_rec_t* next; //Pointer to next object registered in OJBECT DB
|
||||||
|
void* ptr; //Pointer to object which it registered
|
||||||
|
unsigned int units; //No. of objects created
|
||||||
|
struct_db_rec_t* struct_rec; //Structure type it belongs to...
|
||||||
|
mld_boolean_t is_visited; //Used for Graph traversal
|
||||||
|
mld_boolean_t is_root; //Is this object is Root object
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _object_db_ {
|
||||||
|
|
||||||
|
struct_db_t* struct_db; //Pointer to OBJECT DATABASE
|
||||||
|
object_db_rec_t* head; //Head of the DB
|
||||||
|
unsigned int count; //No. of registered OBJECT in DB
|
||||||
|
|
||||||
|
} object_db_t;
|
||||||
|
|
||||||
|
|
||||||
|
/****Printing functions for dumping object db****/
|
||||||
|
|
||||||
|
void
|
||||||
|
print_object_rec(object_db_rec_t* obj_rec, int i);
|
||||||
|
|
||||||
|
void
|
||||||
|
print_object_db(object_db_t* object_db);
|
||||||
|
|
||||||
|
/****Printing functions for dumping object db****/
|
||||||
|
|
||||||
|
|
||||||
|
/*****API to calloc the object******/
|
||||||
|
|
||||||
|
|
||||||
|
void*
|
||||||
|
xcalloc(object_db_t* object_db, char* struct_name, int units);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****API to calloc the object******/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****APIs to register root objects******/
|
||||||
|
|
||||||
|
void
|
||||||
|
mld_register_root_object(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);
|
||||||
|
|
||||||
|
/*****APIs to register root objects******/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Declaration for OBJECT DATABASE
|
||||||
|
*/
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
7
src/CMakeLists.txt
Normal file
7
src/CMakeLists.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
set(MLD_SRC "mld.c")
|
||||||
|
|
||||||
|
add_library(${MLD_LIB} STATIC
|
||||||
|
${MLD_SRC})
|
||||||
|
|
||||||
|
target_include_directories(${MLD_LIB} PUBLIC
|
||||||
|
${HEADER_DIR})
|
||||||
152
src/mld.c
Normal file
152
src/mld.c
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "mld.h"
|
||||||
|
#include "css.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <memory.h>
|
||||||
|
|
||||||
|
char* DATA_TYPE[] = { "UINT8", "UINT32", "INT32",
|
||||||
|
"CHAR", "OBJ_PTR", "VOID_PTR", "FLOAT",
|
||||||
|
"DOUBLE", "OBJ_STRUCT" };
|
||||||
|
|
||||||
|
/**********Printing functions**********/
|
||||||
|
|
||||||
|
void
|
||||||
|
print_structure_rec(struct_db_rec_t* struct_rec) {
|
||||||
|
|
||||||
|
if (!struct_rec)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int j = 0;
|
||||||
|
|
||||||
|
field_info_t* field = NULL;
|
||||||
|
printf(ANSI_COLOR_CYAN "|--------------------------------------------------------------|\n" ANSI_COLOR_RESET);
|
||||||
|
printf(ANSI_COLOR_YELLOW "| %-20s | size = %-8d | #flds = %-3d |\n" ANSI_COLOR_RESET,
|
||||||
|
struct_rec->struct_name, struct_rec->ds_size, struct_rec->n_fields);
|
||||||
|
|
||||||
|
printf(ANSI_COLOR_CYAN "|--------------------------------------------------------------|--------------------------------------------------------------------------------------|\n" ANSI_COLOR_RESET);
|
||||||
|
|
||||||
|
for (j = 0; j < struct_rec->n_fields; j++) {
|
||||||
|
field = &struct_rec->fields[j];
|
||||||
|
printf(" %-20s |", "");
|
||||||
|
printf("%-3d %-20s | dtype = %-15s | size = %-5d | offset = %-6d | nstructname = %-20s |\n",
|
||||||
|
j, field->fname, DATA_TYPE[field->dtype], field->size, field->offset, field->nested_str_name);
|
||||||
|
printf(" %-20s |", "");
|
||||||
|
printf(ANSI_COLOR_CYAN "----------------------------------------------------------------------------------------------------------------------------|\n" ANSI_COLOR_RESET);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
print_structure_db(struct_db_t* struct_db) {
|
||||||
|
|
||||||
|
if (!struct_db)
|
||||||
|
return;
|
||||||
|
printf("printing STRUCTURE DATABASE\n");
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
struct_db_rec_t* struct_rec = NULL;
|
||||||
|
struct_rec = struct_db->head;
|
||||||
|
printf("No of Structures Registered = %d\n", struct_db->count);
|
||||||
|
while (struct_rec) {
|
||||||
|
|
||||||
|
/****%p format specifier is used to print value of void* pointer in hexadecimal format(prints the address value)****/
|
||||||
|
printf("Structure No : %d (%p)\n", i++, struct_rec);
|
||||||
|
print_structure_rec(struct_rec);
|
||||||
|
struct_rec = struct_rec->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********Printing functions**********/
|
||||||
|
|
||||||
|
|
||||||
|
/******Function to add the structure record to structure db******/
|
||||||
|
|
||||||
|
/*return 0 on success, -1 on failure from some reason*/
|
||||||
|
int
|
||||||
|
add_structure_to_struct_db(struct_db_t* struct_db, struct_db_rec_t* struct_rec) {
|
||||||
|
|
||||||
|
struct_db_rec_t* head = struct_db->head;
|
||||||
|
|
||||||
|
if (!head) {
|
||||||
|
struct_db->head = struct_rec;
|
||||||
|
struct_rec->next = NULL;
|
||||||
|
struct_db->count++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct_rec->next = head;
|
||||||
|
struct_db->head = struct_rec;
|
||||||
|
struct_db->count++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******Function to add the structure record to structure db******/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/******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_look_up(struct_db_t* struct_db, char* struct_name) {
|
||||||
|
|
||||||
|
if (!struct_db || !struct_name)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
struct_db_rec_t* struct_rec = struct_db->head;
|
||||||
|
|
||||||
|
unsigned int sz_db = struct_db->count;
|
||||||
|
|
||||||
|
struct_db_rec_t* desired_rec = NULL;
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
while (i < sz_db) {
|
||||||
|
|
||||||
|
if (!strncmp(struct_rec->struct_name, struct_name, MAX_STRUCTURE_NAME_SIZE)) {
|
||||||
|
desired_rec = struct_rec;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct_rec = struct_rec->next;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return desired_rec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******Function to lookup the structure record in structure db******/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/******Function to lookup the object record in object db******/
|
||||||
|
|
||||||
|
|
||||||
|
static object_db_rec_t*
|
||||||
|
object_db_look_up(object_db_t* object_db,
|
||||||
|
void* ptr) {
|
||||||
|
|
||||||
|
object_db_rec_t* head = object_db->head;
|
||||||
|
if (!head)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
unsigned int sz_db = object_db->count;
|
||||||
|
|
||||||
|
object_db_rec_t* desired_obj = NULL;
|
||||||
|
int i = 0;
|
||||||
|
while (i < sz_db) {
|
||||||
|
|
||||||
|
if (head->ptr == ptr) {
|
||||||
|
desired_obj = head->ptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
head = head->next;
|
||||||
|
i++;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return desired_obj;
|
||||||
|
}
|
||||||
|
/******Function to lookup the object record in object db******/
|
||||||
Reference in New Issue
Block a user