From 19c75d5fe9fde6bb1717c1506a627a38dc4efcd1 Mon Sep 17 00:00:00 2001 From: Felix Queissner Date: Mon, 17 Aug 2015 20:04:14 +0200 Subject: [PATCH] Fixes a lot of memory leaks. Adds malloc monitoring. --- Depfile | 4 ++ Makefile | 48 +++++++++++++----------- include/config.h | 4 ++ include/ker/string.hpp | 4 +- include/ker/vector.hpp | 3 ++ include/malloc.h | 60 +++++++++++++++++++++++++++++ include/stdlib.h | 48 +++++------------------- src/cplusplus.cpp | 8 +++- src/init.c | 6 +++ src/malloc.c | 85 +++++++++++++++++++++++++++++++++++++----- trainOS.pro | 3 +- trainscript/tsvm.cpp | 14 ++++++- 12 files changed, 210 insertions(+), 77 deletions(-) create mode 100644 include/malloc.h diff --git a/Depfile b/Depfile index 2f83128..be96577 100644 --- a/Depfile +++ b/Depfile @@ -37,3 +37,7 @@ obj/main.o: scripts/main.ts .PHONY: run run: qemu-system-i386 -serial stdio -kernel kernel + +.PHONY: debug +debug: + qemu-system-i386 -s -S -serial stdio -kernel kernel diff --git a/Makefile b/Makefile index 1760a36..ef3437e 100644 --- a/Makefile +++ b/Makefile @@ -34,12 +34,12 @@ kernel: obj/tsvm.o obj/dynamic.o obj/intr_common_handler.o obj/multiboot.o obj/s # src/console.c obj/console.o: src/console.c include/console.h include/stdlib.h \ - include/varargs.h include/config.h + include/varargs.h include/config.h include/malloc.h $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/console.c # src/init.c obj/init.o: src/init.c include/kernel.h include/stdlib.h include/varargs.h \ - include/config.h include/console.h include/interrupts.h \ + include/config.h include/malloc.h include/console.h include/interrupts.h \ include/cpustate.h include/pmm.h include/multiboot.h include/vmm.h \ include/timer.h include/serial.h $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/init.c @@ -47,27 +47,29 @@ obj/init.o: src/init.c include/kernel.h include/stdlib.h include/varargs.h \ # src/interrupts.c obj/interrupts.o: src/interrupts.c include/interrupts.h include/cpustate.h \ include/console.h include/stdlib.h include/varargs.h include/config.h \ - include/io.h src/intr_stubs.h + include/malloc.h include/io.h src/intr_stubs.h $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/interrupts.c # src/malloc.c obj/malloc.o: src/malloc.c include/kernel.h include/stdlib.h \ - include/varargs.h include/config.h include/console.h include/serial.h + include/varargs.h include/config.h include/malloc.h include/console.h \ + include/serial.h $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/malloc.c # src/pmm.c obj/pmm.o: src/pmm.c include/pmm.h include/multiboot.h include/kernel.h \ - include/stdlib.h include/varargs.h include/config.h include/console.h + include/stdlib.h include/varargs.h include/config.h include/malloc.h \ + include/console.h $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/pmm.c # src/serial.c obj/serial.o: src/serial.c include/io.h include/serial.h include/stdlib.h \ - include/varargs.h include/config.h + include/varargs.h include/config.h include/malloc.h $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/serial.c # src/stdlib.c obj/stdlib.o: src/stdlib.c include/stdlib.h include/varargs.h \ - include/config.h include/kernel.h + include/config.h include/malloc.h include/kernel.h $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/stdlib.c # src/timer.c @@ -77,13 +79,13 @@ obj/timer.o: src/timer.c include/timer.h include/kernel.h \ # src/vmm.c obj/vmm.o: src/vmm.c include/config.h include/vmm.h include/pmm.h \ - include/multiboot.h include/stdlib.h include/varargs.h include/console.h \ - include/kernel.h + include/multiboot.h include/stdlib.h include/varargs.h include/malloc.h \ + include/console.h include/kernel.h $(CC) $(FLAGS) $(CCFLAGS) -o $@ -c src/vmm.c # trainscript/tsvm.cpp obj/tsvm.o: trainscript/tsvm.cpp include/stdlib.h include/varargs.h \ - include/config.h include/console.h trainscript/common.h \ + include/config.h include/malloc.h include/console.h trainscript/common.h \ trainscript/tsvm.hpp include/ker/string.hpp include/ker/vector.hpp \ include/ker/new.hpp include/ker/dictionary.hpp include/kernel.h \ include/ker/pair.hpp trainscript/typeid.hpp \ @@ -93,29 +95,29 @@ obj/tsvm.o: trainscript/tsvm.cpp include/stdlib.h include/varargs.h \ # src/cplusplus.cpp obj/cplusplus.o: src/cplusplus.cpp include/stdlib.h include/varargs.h \ - include/config.h include/console.h include/ker/new.hpp + include/config.h include/malloc.h include/console.h include/ker/new.hpp $(CXX) $(FLAGS) $(CXXFLAGS) -o $@ -c src/cplusplus.cpp # src/vm.cpp obj/vm.o: src/vm.cpp include/stdlib.h include/varargs.h include/config.h \ - include/timer.h include/dynamic.h src/../trainscript/tsvm.hpp \ - include/console.h include/ker/string.hpp include/ker/vector.hpp \ - include/ker/new.hpp include/ker/dictionary.hpp include/kernel.h \ - include/ker/pair.hpp src/../trainscript/typeid.hpp + include/malloc.h include/timer.h include/dynamic.h \ + src/../trainscript/tsvm.hpp include/console.h include/ker/string.hpp \ + include/ker/vector.hpp include/ker/new.hpp include/ker/dictionary.hpp \ + include/kernel.h include/ker/pair.hpp src/../trainscript/typeid.hpp $(CXX) $(FLAGS) $(CXXFLAGS) -o $@ -c src/vm.cpp # obj/trainscript.yy.cpp obj/trainscript.yy.o: obj/trainscript.yy.cpp include/string.h \ - include/stdlib.h include/varargs.h include/config.h trainscript/common.h \ - trainscript/tsvm.hpp include/console.h include/ker/string.hpp \ - include/ker/vector.hpp include/ker/new.hpp include/ker/dictionary.hpp \ - include/kernel.h include/ker/pair.hpp trainscript/typeid.hpp \ - obj/trainscript.tab.hpp + include/stdlib.h include/varargs.h include/config.h include/malloc.h \ + trainscript/common.h trainscript/tsvm.hpp include/console.h \ + include/ker/string.hpp include/ker/vector.hpp include/ker/new.hpp \ + include/ker/dictionary.hpp include/kernel.h include/ker/pair.hpp \ + trainscript/typeid.hpp obj/trainscript.tab.hpp $(CXX) -iquotetrainscript $(FLAGS) $(CXXFLAGS) -o $@ -c obj/trainscript.yy.cpp # obj/trainscript.tab.cpp obj/trainscript.tab.o: obj/trainscript.tab.cpp include/stdlib.h \ - include/varargs.h include/config.h trainscript/common.h \ + include/varargs.h include/config.h include/malloc.h trainscript/common.h \ trainscript/tsvm.hpp include/console.h include/ker/string.hpp \ include/ker/vector.hpp include/ker/new.hpp include/ker/dictionary.hpp \ include/kernel.h include/ker/pair.hpp trainscript/typeid.hpp \ @@ -158,3 +160,7 @@ obj/main.o: scripts/main.ts .PHONY: run run: qemu-system-i386 -serial stdio -kernel kernel + +.PHONY: debug +debug: + qemu-system-i386 -s -S -serial stdio -kernel kernel diff --git a/include/config.h b/include/config.h index cd6a1a0..df60262 100644 --- a/include/config.h +++ b/include/config.h @@ -15,3 +15,7 @@ //* #define USE_MAGIC_SECURED_MALLOC //*/ + +//* +#define ENABLE_MALLOC_MONITORING +//*/ diff --git a/include/ker/string.hpp b/include/ker/string.hpp index a25c313..a4a1fb2 100644 --- a/include/ker/string.hpp +++ b/include/ker/string.hpp @@ -136,8 +136,8 @@ namespace ker void copyFrom(const uint8_t *bytes, size_t length) { if(this->mText != nullptr) { - // free(this->mText); - } + free(this->mText); + } this->mText = (uint8_t*)malloc(length + 1); memcpy(this->mText, bytes, length); this->mLength = length; diff --git a/include/ker/vector.hpp b/include/ker/vector.hpp index b4c67a1..8e9510d 100644 --- a/include/ker/vector.hpp +++ b/include/ker/vector.hpp @@ -66,6 +66,9 @@ namespace ker ~Vector() { if(this->mData != nullptr) { + for(size_t i = 0; i < this->mLength; i++) { + this->mData[i].~T(); + } free(this->mData); } } diff --git a/include/malloc.h b/include/malloc.h new file mode 100644 index 0000000..ed01a73 --- /dev/null +++ b/include/malloc.h @@ -0,0 +1,60 @@ +#pragma once + +#include +#include + +#include "config.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +#if defined(USE_VERBOSE_MALLOC) +void *malloc_d(size_t,const char *,int); +#endif + +#if defined(USE_VERBOSE_FREE) +void free_d(void *,const char*, int); +#endif + +#if defined(ENABLE_MALLOC_MONITORING) +void *_malloc(size_t, const char *, int); + +void* _realloc (void*, size_t, const char *, int); + +#define malloc(size) _malloc((size), __FILE__, __LINE__) +#define realloc(ptr, size) _realloc((ptr), (size), __FILE__, __LINE__) + +#else +/** + * Allocates a block of memory + * @param size Minimum size of the memory block + * @return Pointer to the allocated memory area + */ +void *malloc(size_t size); + +void* realloc (void* ptr, size_t size); +#endif + +/** + * Frees a previously allocated block of memory. + * @param mem The block of memory. + */ +void free(void *mem); + +#if defined(ENABLE_MALLOC_MONITORING) +void malloc_print_list(int freeList); +#endif + +#if defined(__cplusplus) +} +#endif + + +#if defined(USE_VERBOSE_MALLOC) +#define malloc(size) malloc_d((size), __FILE__, __LINE__) +#endif + +#if defined(USE_VERBOSE_FREE) +#define free(ptr) free_d((ptr), __FILE__, __LINE__) +#endif diff --git a/include/stdlib.h b/include/stdlib.h index a898a5e..999e2e8 100644 --- a/include/stdlib.h +++ b/include/stdlib.h @@ -5,6 +5,8 @@ #include "varargs.h" #include "config.h" +#include "malloc.h" + #if defined(__cplusplus) extern "C" { #endif @@ -13,29 +15,6 @@ char *itoa(int value, char *str, int base); int atoi(const char *str); float atof(const char *str); -#if defined(USE_VERBOSE_MALLOC) -void *malloc_d(size_t,const char *,int); -#endif - -#if defined(USE_VERBOSE_FREE) -void free_d(void *,const char*, int); -#endif - -/** - * Allocates a block of memory - * @param size Minimum size of the memory block - * @return Pointer to the allocated memory area - */ -void *malloc(size_t size); - -/** - * Frees a previously allocated block of memory. - * @param mem The block of memory. - */ -void free(void *mem); - -void* realloc (void* ptr, size_t size); - void exit(int errorCode); static inline void *memset(void *ptr, int value, size_t num) @@ -126,13 +105,6 @@ static inline int strcmp(const char *p1, const char *p2) return 0; } -static inline void *calloc(size_t size) -{ - void *mem = malloc(size); - memset(mem, 0, size); - return mem; -} - static inline char * strdup(const char *str) { size_t len = strlen(str) + 1; @@ -141,6 +113,13 @@ static inline char * strdup(const char *str) return n; } +static inline void *calloc(size_t size) +{ + void *mem = malloc(size); + memset(mem, 0, size); + return mem; +} + int sprintf(char *target, const char *format, ...); int vsprintf(char *target, const char *format, va_list vl); @@ -149,12 +128,3 @@ int vsprintf(char *target, const char *format, va_list vl); } #endif - - -#if defined(USE_VERBOSE_MALLOC) -#define malloc(size) malloc_d((size), __FILE__, __LINE__) -#endif - -#if defined(USE_VERBOSE_FREE) -#define free(ptr) free_d((ptr), __FILE__, __LINE__) -#endif diff --git a/src/cplusplus.cpp b/src/cplusplus.cpp index 3fe9e3d..8037fa2 100644 --- a/src/cplusplus.cpp +++ b/src/cplusplus.cpp @@ -6,12 +6,16 @@ void *operator new( size_t size ) { - return calloc( size ); + void *ptr = malloc( size ); + memset(ptr, 0, size); + return ptr; } void *operator new[]( size_t size ) { - return calloc( size ); + void *ptr = malloc( size ); + memset(ptr, 0, size); + return ptr; } void operator delete( void *obj ) diff --git a/src/init.c b/src/init.c index 45f33c4..ebf7332 100644 --- a/src/init.c +++ b/src/init.c @@ -208,8 +208,14 @@ void init(const MultibootStructure *mbHeader) vm_start(); + irq_disable(); + kputs("\x12\x04trainOS stopped.\x12\x07!\n"); +#if defined(ENABLE_MALLOC_MONITORING) + malloc_print_list(0); +#endif + while(1); } diff --git a/src/malloc.c b/src/malloc.c index 0913326..2f3268a 100644 --- a/src/malloc.c +++ b/src/malloc.c @@ -15,6 +15,10 @@ typedef struct List size_t length; size_t used; struct List *next; +#if defined(ENABLE_MALLOC_MONITORING) + const char *allocationFile; + int allocationLine; +#endif } List; size_t mallocCount = 0, freeCount = 0; @@ -26,6 +30,45 @@ static char * const malloc_heap_end = (char *)0x10000000; List *listBegin = nullptr; +#if defined(ENABLE_MALLOC_MONITORING) +void malloc_print_list(int freeList) +{ + List *list = listBegin; + serial_printf(SERIAL_COM1, "malloc list: \n"); + size_t count = 0; + while(list != nullptr) + { +#if defined(USE_MAGIC_SECURED_MALLOC) + if(list->magic != 0xDEADBEEF) { + die("malloc::print_list.InvalidMagicNumber"); + } +#endif + if(freeList || list->used) { + serial_printf(SERIAL_COM1, + "[%x -> %x] (%s:%d) %d %d\n", + list, + list->next, + list->used ? list->allocationFile : "", + list->used ? list->allocationLine : "", + list->used, + list->length); + kprintf("[%x -> %x] (%s:%d) %d %d\n", + list, + list->next, + list->used ? list->allocationFile : "", + list->used ? list->allocationLine : "", + list->used, + list->length); + if(list->used) { + count++; + } + } + list = list->next; + } + kprintf("Unfreed objects: %d\n", count); + serial_printf(SERIAL_COM1, "Unfreed objects: %d\n", count); +} +#else static void print_list() { List *list = listBegin; @@ -41,6 +84,7 @@ static void print_list() list = list->next; } } +#endif static void defragment() { @@ -61,7 +105,11 @@ static void defragment() } } +#if defined(ENABLE_MALLOC_MONITORING) +void *_malloc(size_t len, const char *file, int line) +#else void *malloc(size_t len) +#endif { // Prevent fragmentation, sacrifice memory if(len < minimumAllocSize) { @@ -85,7 +133,11 @@ void *malloc(size_t len) cursor = cursor->next; } if(cursor == nullptr) { +#if defined(ENABLE_MALLOC_MONITORING) + malloc_print_list(1); +#else print_list(); +#endif die_extra("malloc.OutOfMemory", itoa(len, nullptr, 10)); } @@ -93,17 +145,12 @@ void *malloc(size_t len) die("malloc.FragmentationFailure"); } - if(cursor->length == len) - { - cursor->used = 1; - } - else + if(cursor->length != len) { // Store total length size_t newLength = cursor->length - sizeof(List) - len; // Allocate the memory - cursor->used = 1; cursor->length = len; // Fragment list @@ -118,15 +165,29 @@ void *malloc(size_t len) cursor->next = newl; } + cursor->used = 1; +#if defined(ENABLE_MALLOC_MONITORING) + cursor->allocationFile = file; + cursor->allocationLine = line; +#endif + allocatedMemory += len; mallocCount++; return (void*)((char*)cursor + sizeof(List)); } +#if defined(ENABLE_MALLOC_MONITORING) +void* _realloc (void* ptr, size_t size, const char *file, int line) +#else void* realloc (void* ptr, size_t size) +#endif { +#if defined(ENABLE_MALLOC_MONITORING) + void *n = _malloc(size, file, line); +#else void *n = malloc(size); +#endif memcpy(n, ptr, size); free(ptr); return n; @@ -139,13 +200,13 @@ void free(void *ptr) return; } if((uintptr_t)ptr < (uintptr_t)malloc_heap_start) { - die_extra("free.InvalidFree", itoa(ptr, nullptr, 16)); + die_extra("free.InvalidFree", itoa((int)ptr, nullptr, 16)); } freeCount++; List *entry = (List*)((char*)ptr - sizeof(List)); if(entry->used == 0) { - die_extra("free.InvalidBlock", itoa(ptr, nullptr, 16)); + die_extra("free.InvalidBlock", itoa((int)ptr, nullptr, 16)); } #if defined(USE_MAGIC_SECURED_MALLOC) if(entry->magic != 0xDEADBEEF) { @@ -175,8 +236,12 @@ void *malloc_d(size_t len, const char *file, int line) serial_write_str(SERIAL_COM1, itoa(line, nullptr, 10)); serial_write_str(SERIAL_COM1, ": "); +#if defined(ENABLE_MALLOC_MONITORING) + void *ptr = _malloc(len, file, line); +#else void *ptr = malloc(len); - serial_write_str(SERIAL_COM1, itoa(ptr, nullptr, 16)); +#endif + serial_write_str(SERIAL_COM1, itoa((int)ptr, nullptr, 16)); serial_write_str(SERIAL_COM1, "\n"); return ptr; @@ -192,7 +257,7 @@ void free_d(void *ptr, const char *file, int line) serial_write_str(SERIAL_COM1, "Free "); serial_write_str(SERIAL_COM1, itoa(entry->length, nullptr, 10)); serial_write_str(SERIAL_COM1, " bytes at "); - serial_write_str(SERIAL_COM1, itoa(ptr, nullptr, 16)); + serial_write_str(SERIAL_COM1, itoa((int)ptr, nullptr, 16)); serial_write_str(SERIAL_COM1, " in "); serial_write_str(SERIAL_COM1, file); serial_write_str(SERIAL_COM1, ":"); diff --git a/trainOS.pro b/trainOS.pro index c87c181..4f63c0a 100644 --- a/trainOS.pro +++ b/trainOS.pro @@ -42,7 +42,8 @@ HEADERS += \ include/ker/new.hpp \ include/dynamic.h \ include/config.h \ - include/serial.h + include/serial.h \ + include/malloc.h DISTFILES += \ asm/intr_common_handler.S \ diff --git a/trainscript/tsvm.cpp b/trainscript/tsvm.cpp index a792eb6..ed84a82 100644 --- a/trainscript/tsvm.cpp +++ b/trainscript/tsvm.cpp @@ -96,6 +96,8 @@ namespace trainscript { LocalContext context(this->module); + ker::Vector temporaries; + for(auto var : this->module->variables) { context.add(var.first, var.second); @@ -115,14 +117,22 @@ namespace trainscript if(this->mArguments[i].second != arguments[i].type) { die_extra("ScriptMethod::invoke", "Invalid argument type."); } - context.add(this->mArguments[i].first, new Variable(arguments[i])); + auto *v = new Variable(arguments[i]); + temporaries.append(v); + context.add(this->mArguments[i].first, v); } for(auto local : this->mLocals) { - context.add(local.first, new Variable { local.second, 0 }); + auto *v = new Variable { local.second, 0 }; + temporaries.append(v); + context.add(local.first, v); } this->block->execute(context); + for(auto *var : temporaries) { + delete var; + } + return returnVariable; }