Emre Kilic
Emre Kilic

Reputation: 1

How to sanitize allocated memory in C before using free function?

I have created a nested struct called employee. I allocate a space for an employee from heap using malloc. Then, I release the space using free. As far as I know, free function only marks a location available for the future allocation. Hence, the content of allocated memory remains in the memory and it causes heap inspection.

Structs I defined in the beginning of my program as follow.

struct address{
    char *city;
    int zip;
}

struct employee{
    char *name;
    struct address add;
}

I implemented a function called sanitize to replace the private fields with junk values (0xAA in this case). Then, I tested sanitize in the main function.

void sanitize(char *ptr, int size){
    memset(ptr, 0xAA, size);
}

int main()
{
    struct employee* emp;
    emp = malloc(sizeof(char) * 40);
    emp->name = "John";
    emp->add.city = "London";
    emp->add.zip = 221;
    printf("%s\n", emp->add.city);
    sanitize(&(emp->add), sizeof(struct address));
    printf("%s\n", emp->add.city);
    return 0;
}

During runtime I get segmentation fault. What is wrong with my program? How and in which order shoul I sanitize nested structs?

Thanks in advance.

Upvotes: 0

Views: 326

Answers (1)

Dúthomhas
Dúthomhas

Reputation: 10083

Make sure to properly allocate memory for your objects. Functions to do it help a lot.

struct employee *new_employee()
{
  struct employee *emp = (struct employee*)malloc( sizeof(struct employee) );
  if (emp)
  {
    emp->name = NULL;
    emp->add.city = NULL;
  }
  return emp;
}

Likewise, create a function to destroy an employee:

struct employee *destroy_employee( struct employee *emp )
{
  if (emp)
  {
    if (emp->name)     free( emp->name );
    if (emp->add.city) free( emp->add.city );
    free( emp );
  }
  return NULL;
}

Likewise your sanitize function needs to know about employees:

void sanitize_employee( struct employee *emp )
{
  if (emp)
  {
    if (emp->name)     memset( emp->name,     0xAA, strlen( emp->name     ) );
    if (emp->add.city) memset( emp->add.city, 0xAA, strlen( emp->add.city ) );
    emp->add.zip = 0xAAAAAAAA;
  }
}

Now you can easily create and destroy employees:

struct employee *emp = new_employee();
emp->name = strdup( "John" );
emp->add.city = strdup( "London" );
emp->add.zip = 221;

...

sanitize_employee( emp );
emp = destroy_employee( emp );

Notice how we take care to always allocate space for every object, and delete each object appropriately. You could very well combine the sanitize and destroy functions.

There is an important concern to your structure design. If you change an employee’s details (for example, changing his name) it is possible that your sanitization can fail and employee data can be left unsanitized. For this you should make it a strict policy to never mutate an employee structure: make it const, or make additional functions to mutate the data and perform proper sanitization and memory management (sanitize, free the old value, strdup the new value).

You might simply want to create a fixed-size record to handle employee data. This would simplify your life significantly and free you from having to deal with quite as many memory-managing employee functions.

Upvotes: 1

Related Questions