LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Software (https://www.linuxquestions.org/questions/linux-software-2/)
-   -   How to fix this: glibc detected: double free or corruption (https://www.linuxquestions.org/questions/linux-software-2/how-to-fix-this-glibc-detected-double-free-or-corruption-912534/)

mrjextreme6 11-08-2011 01:56 PM

How to fix this: glibc detected: double free or corruption
 
I am trying to simulate a memory management system using first-fit algorithm. It mallocs a chunk of memory space and creates a threadpool where each thread allocates pieces of the memory and then frees it. Clearly my algorithm needs work because they all keep writing to the same base address (nil) but I doubt that's causing the issue. When I close the program and attempt to free the memory, I get the following output:


:~/Documents/OS_3$ ./mem_manager 5
Thread 0 allocated to base (nil) with size 1383
Free Space Left: 2713

Here!
Thread 1 allocated to base (nil) with size 2153
Free Space Left: 560

Thread 2 could not allocate size 3153
Thread 3 could not allocate size 1098
Thread 4 could not allocate size 3881
Thread 4 could not allocate size 2234
Here!
Thread 3 allocated to base (nil) with size 498
Free Space Left: 62

^C

*** glibc detected *** ./mem_manager: double free or corruption (!prev): 0x0000000001362010 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x78a96)[0x7f3df63aea96]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x6c)[0x7f3df63b2d7c]
./mem_manager[0x400e7c]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7f3df635730d]
./mem_manager[0x4008f9]
======= Memory map: ========
.....(etc.)



Code:


#include <stdio.h>
#include <stdlib.h>
#include <pthread.h> // Object files must be compiled with gcc's -lpthread flag
#include <unistd.h>
#include <signal.h>

#define MAX_SIZE 4096 // Max memory size of system
#define MAX_WAIT_TIME 10 // Maximum sleep time
#define INVALID -1
#define ERROR INVALID

typedef struct page { // Page data type
  unsigned char *base;
  int size;
  int owner;
} Page;

typedef struct pageTable { // Page table data type
  Page *table;
  int number;
  int owner;
} PageTable;

typedef struct memoryBlock { // Memory block data type
  unsigned char *memBlock; // Pointer to allocated memory block
  int freeSpace; // Number of unallocated bytes within memory block
} MemoryBlock;

// Global data
MemoryBlock memory; // Memory block
PageTable pages; // Page table
int numThreads; // Number of threads
unsigned char **base_ptrs; // Array of base pointers
int running  = 1; // Signal handler variable

void signalHandler(int sig);
unsigned char *memory_malloc(MemoryBlock *p_memory, PageTable *p_pages, int size);
void memory_free(MemoryBlock *p_memory, PageTable *p_pages, unsigned char *base, unsigned char **base_ptrs);
unsigned char *first_fit(MemoryBlock *p_memory, PageTable *p_pages, int size);
void *thread(void *ptr);

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // Initialize mutex

int main(int argc, char *argv[])
{
  int i;

  signal(SIGINT, signalHandler); // Initialize signal handler

  if (argc < 2) // Is input missing?
    {
      fprintf(stderr, "ERROR: Number of threads unspecified\n");
      exit(1);
    }

  numThreads = atoi(argv[1]);

  if (numThreads < 1) // Is number of threads greater than zero?
    {
      fprintf(stderr, "ERROR: Number of threads less than 1\n");
      exit(1);
    }

  if ((memory.memBlock = (unsigned char*) malloc(sizeof(unsigned char) * MAX_SIZE)) == NULL)
    {
      fprintf(stderr, "ERROR: Not enough memory in system\n");
      exit(1);
    }

  memory.freeSpace = MAX_SIZE;

  // Allocate page table
  if ((pages.table = (Page *) malloc(sizeof(Page) * numThreads)) == NULL)
    {
      fprintf(stderr, "ERROR: Not enough memory for page table\n");
      free(memory.memBlock);
      memory.memBlock = NULL;
      memory.freeSpace = 0x00;
      exit(1);
    }

  // Initialize page table
  for (i = 0; i < numThreads; i++)
    {
      pages.table[i].base = NULL;
      pages.table[i].size = 0x00;
      pages.table[i].owner = INVALID;
    }

  pages.number = numThreads;

  // Allocate base pointer array
  if ((base_ptrs = (unsigned char **) malloc(sizeof(unsigned char *) * numThreads)) == NULL)
    {
      fprintf(stderr, "ERROR: Not enough memory for base pointer array\n");
      free(memory.memBlock);
      free(pages.table);
      memory.memBlock = NULL;
      memory.freeSpace = 0x00;
      pages.table = NULL;
      pages.number = 0x00;
      exit(1);
    }

  // Initialize base pointer array
  for (i = 0; i < numThreads; i++)
    {
      base_ptrs[i] = NULL;
    }

  pthread_t threadPool[numThreads]; // Thread pool
  int threadIDs[numThreads]; // Thread IDs

  // Create threads
  for (i = 0; i < numThreads; i++)
    {
      threadIDs[i] = i;
      if (pthread_create(&threadPool[i], NULL, thread, (void *)&threadIDs[i]))
        {
          fprintf(stderr, "ERROR: thread %d creation failure\n", i);
          free(memory.memBlock);
          free(pages.table);
          free(base_ptrs);
          memory.memBlock = NULL;
          memory.freeSpace = 0x00;
          pages.table = NULL;
          pages.number = 0x00;
          exit(1);
        }
    }

  // Join threads
  for (i = 0; i < numThreads; i++)
    {
      pthread_join(threadPool[i], NULL);
    }

  // Free memory
  free(memory.memBlock);
  free(pages.table);
  free(base_ptrs);
  memory.memBlock = NULL;
  memory.freeSpace = 0x00;
  pages.table = NULL;
  pages.number = 0x00;

  printf("\n\nAll threads returned successfully!\n\n");

  return 0;
}

// Signal Handler
void signalHandler(int sig)
{
  running = 0;
  return;
}

// Allocates chunk of memory to a thread
unsigned char *memory_malloc(MemoryBlock *p_memory, PageTable *p_pages, int size)
{
  if (p_memory->freeSpace < size) // Is there enough total free memory?
    {
      return NULL;
    }

  else
    {
      return first_fit(p_memory, p_pages, size);
    }
}

void memory_free(MemoryBlock *p_memory, PageTable *p_pages, unsigned char *base, unsigned char **base_ptrs)
{
  int i, j, k;

  for (i = 0; i < p_pages->number; i++)
    {
      if ((*p_pages).table[i].base == base) // If page match, remove from page table and free space in memory block
        {
          p_memory->freeSpace += (*p_pages).table[i].size;
          base_ptrs[(*p_pages).table[i].owner] = NULL;
          (*p_pages).table[i].size = 0x00;
          (*p_pages).table[i].owner = INVALID;
          break;
        }
    }

  k = i;

  // Group all freed blocks
  for (j = i; j < (p_pages->number - 1); j++)
    {
      if ((*p_pages).table[j + 1].base)
        {
          (*p_pages).table[k].size = (*p_pages).table[j + 1].size;
          (*p_pages).table[k].owner = (*p_pages).table[j + 1].owner;
          base_ptrs[(*p_pages).table[k].owner] = (*p_pages).table[k].base;
          (*p_pages).table[k + 1].base = (*p_pages).table[k].base + (*p_pages).table[k].size;
          k++;
        }
    }

  (*p_pages).table[k].base = NULL;
  (*p_pages).table[k].size = 0x00;
  (*p_pages).table[k].owner = INVALID;

  return;
}

unsigned char *first_fit(MemoryBlock *p_memory, PageTable *p_pages, int size)
{
  int i,  j;

  for (i = 0; i < (p_pages->number - 1); i++)
    {
      if (((*p_pages).table[i].base != NULL) && ((*p_pages).table[i + 1].base == NULL))
        {
          printf("Here!\n");
          for (j = (i + 1); j < p_pages->number; j++)
            {
              if ((*p_pages).table[j].base)
                {
                  if (((*p_pages).table[j].base - ((*p_pages).table[i].base + (*p_pages).table[i].size)) >= size)
                    {
                      (*p_pages).table[i + 1].base = (*p_pages).table[i].base + (*p_pages).table[i].size;
                      (*p_pages).table[i + 1].size = size;
                      p_memory->freeSpace -= size;
                      return (*p_pages).table[i + 1].base;
                    }
                  else
                    {
                      j = p_pages->number + 1;
                    }
                }
            }
          if (j == p_pages->number)
            {
              (*p_pages).table[i + 1].base = (*p_pages).table[i].base + (*p_pages).table[i].size;
              (*p_pages).table[i + 1].size = size;
              p_memory->freeSpace -= size;
              return (*p_pages).table[i + 1].base;
            }
        }
    }
  (*p_pages).table[0].base = (*p_memory).memBlock;
  (*p_pages).table[0].size = size;
  p_memory->freeSpace -= size;
  return (*p_pages).table[0].base;
}

void *thread(void *ptr)
{
  int threadID = *((int *)(ptr));
  int allocated = 0;
  int random_size; // random allocation size
  int random_time; // random sleep time
  void *base_address;

  while (running)
    {
      pthread_mutex_lock(&mutex); // Grab the mutex
      random_size = (int)(((unsigned int)rand()) % MAX_SIZE); // Generate random number of bytes to allocate no greater than MAX_SIZE
      base_address = (void*)base_ptrs[threadID];
      random_time = rand() % MAX_WAIT_TIME;

      if (allocated)
        {
          memory_free(&memory, &pages, base_ptrs[threadID], base_ptrs);
          allocated = 0;
        }
      else
        {
          if ((base_ptrs[threadID] = memory_malloc(&memory, &pages, random_size)))
            {
              printf("Thread %d allocated to base %p with size %d\n", threadID, base_address, random_size);
              printf("Free Space Left: %d\n\n", memory.freeSpace);
              allocated = 1;
            }
          else
            {
              printf("Thread %d could not allocate size %d\n", threadID, random_size);
              allocated = 0;
            }
        }
      pthread_mutex_unlock(&mutex);

      sleep(random_time);
    }

  return (void *)NULL;
}

I suspect this has to do with my attempt to free my **base_ptrs variable.

Does anyone have any suggestions please?

Thank you!

johnsfine 11-09-2011 06:54 AM

Please use CODE tags around your code so you can preserve the indentation.

I'll look at your code later anyway to see if I can easily spot the bug. But others might choose not to look at it because you didn't use CODE tags.

mrjextreme6 11-09-2011 10:01 AM

Thank you for the advice. I've revised my thread post.

I figured out the algorithm issue but I still get the glibc error when I attempt to free my allocated memory.

mrjextreme6 11-09-2011 03:58 PM

Nevermind, I figured out the problem.

Turns out I forgot set my pages.table[].owner values which I used as indexes for memory allocation. Since I didn't set them, the program started accessing pointers outside my array.

Thanks though!


All times are GMT -5. The time now is 11:27 AM.