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!
|