Fixes a lot of memory leaks. Adds malloc monitoring.
This commit is contained in:
parent
90eb432c50
commit
19c75d5fe9
12 changed files with 210 additions and 77 deletions
4
Depfile
4
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
|
||||
|
|
48
Makefile
48
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
|
||||
|
|
|
@ -15,3 +15,7 @@
|
|||
//*
|
||||
#define USE_MAGIC_SECURED_MALLOC
|
||||
//*/
|
||||
|
||||
//*
|
||||
#define ENABLE_MALLOC_MONITORING
|
||||
//*/
|
||||
|
|
|
@ -136,7 +136,7 @@ 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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
60
include/malloc.h
Normal file
60
include/malloc.h
Normal file
|
@ -0,0 +1,60 @@
|
|||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#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
|
|
@ -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
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
85
src/malloc.c
85
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, ":");
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -96,6 +96,8 @@ namespace trainscript
|
|||
{
|
||||
LocalContext context(this->module);
|
||||
|
||||
ker::Vector<Variable*> 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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue