Пример #1
0
void __wrap_free(void *ptr)
{
	unsigned long addr = (unsigned long) ptr;

	/*
	 * We need to know how the allocation happened, so it can be correctly
	 * freed.  This is done by seeing what region of memory the pointer is
	 * in -
	 * 	physical memory - kmalloc/kfree
	 *	kernel virtual memory - vmalloc/vfree
	 * 	anywhere else - malloc/free
	 * If kmalloc is not yet possible, then either high_physmem and/or
	 * end_vm are still 0 (as at startup), in which case we call free, or
	 * we have set them, but anyway addr has not been allocated from those
	 * areas. So, in both cases __real_free is called.
	 *
	 * CAN_KMALLOC is checked because it would be bad to free a buffer
	 * with kmalloc/vmalloc after they have been turned off during
	 * shutdown.
	 * XXX: However, we sometimes shutdown CAN_KMALLOC temporarily, so
	 * there is a possibility for memory leaks.
	 */

	if ((addr >= uml_physmem) && (addr < high_physmem)) {
		if (kmalloc_ok)
			kfree(ptr);
	}
	else if ((addr >= start_vm) && (addr < end_vm)) {
		if (kmalloc_ok)
			vfree(ptr);
	}
	else __real_free(ptr);
}
Пример #2
0
void *__wrap_realloc(void *p, size_t size)
{
	void *n;
	// ptr from mem2
	if(((u32)p & 0x10000000) != 0 || (p == 0 && size > MEM2_PRIORITY_SIZE))
	{
		n = g_mem2gp.reallocate(p, size);
		if(n != 0)
			return n;
		n = __real_malloc(size);
		if(n == 0)
			return 0;
		if(p != 0)
		{
			memcpy(n, p, MEM2_usableSize(p) < size ? MEM2_usableSize(p) : size);
			g_mem2gp.release(p);
		}
		return n;
	}
	// ptr from malloc
	n = __real_realloc(p, size);
	if(n != 0)
		return n;
	n = g_mem2gp.allocate(size);
	if(n == 0)
		return 0;
	if(p != 0)
	{
		memcpy(n, p, __real_malloc_usable_size(p) < size ? __real_malloc_usable_size(p) : size);
		__real_free(p);
	}
	return n;
}
Пример #3
0
extern "C" NS_EXPORT jobject JNICALL
Java_org_mozilla_goanna_sqlite_SQLiteBridge_sqliteCall(JNIEnv* jenv, jclass,
        jstring jDb,
        jstring jQuery,
        jobjectArray jParams,
        jlongArray jQueryRes)
{
    JNI_Setup(jenv);

    int rc;
    jobject jCursor = NULL;
    const char* dbPath;
    sqlite3 *db;
    char* errorMsg;

    dbPath = jenv->GetStringUTFChars(jDb, NULL);
    rc = f_sqlite3_open(dbPath, &db);
    jenv->ReleaseStringUTFChars(jDb, dbPath);
    if (rc != SQLITE_OK) {
        asprintf(&errorMsg, "Can't open database: %s\n", f_sqlite3_errmsg(db));
        LOG("Error in SQLiteBridge: %s\n", errorMsg);
        JNI_Throw(jenv, "org/mozilla/goanna/sqlite/SQLiteBridgeException", errorMsg);
        // errorMsg is allocated by asprintf, it needs to be freed by libc.
        __real_free(errorMsg);
    } else {
        jCursor = sqliteInternalCall(jenv, db, jQuery, jParams, jQueryRes);
    }
    f_sqlite3_close(db);
    return jCursor;
}
Пример #4
0
/*
 * __wrap_free - free wrapper function
 */
void __wrap_free(void *ptr)
{
	printf("@ %s:[%p] - %p\n", program_invocation_short_name
		, __builtin_return_address(0)
		, ptr
	);
	__real_free(ptr);
}
Пример #5
0
void __wrap_free(void *addr) {
	if (EarlyMallocEnabled) {
		early_free(addr);
	}
	enter_kernel();
	__real_free(addr);
	leave_kernel();
}
Пример #6
0
void __wrap_free( void *ptr )
{
	LockAlloc();

	__real_free( ptr );

	UnlockAlloc();
}
Пример #7
0
void operator delete[](void* ptr) throw()
{
	printf("@ %s:[%p] - %p\n", program_invocation_short_name
		, __builtin_return_address(0)
		, ptr
	);
	__real_free(ptr);
}
Пример #8
0
void __wrap_free(void *p)
{
	if(!p)
		return;

	if(((u32)p & 0x10000000) != 0)
		g_mem2gp.release(p);
	else
		__real_free(p);
}
Пример #9
0
extern "C" void wrap(free)(void *p)
{
	init_lib();

	void* p1 = STUB_PTR(p);

	if (p1)
		fibjs::MemPool::global().remove(p1);

	__real_free(p1);
}
Пример #10
0
	void __wrap_free(void *p)
	{
		if(!p)
			return;
		if(((u32)p < (u32)&__init_start - 0x100 && (u32)p >= (u32)0x80004000) || ((u32)p > (u32)APPLOADER_START && (u32)p < (u32)APPLOADER_END))
			MEM1_free(p);
		else if((u32)p & 0x10000000)
			MEM2_free(p);
		else		
			__real_free(p);
	}
Пример #11
0
/*
 * Expires an object descriptor and decrements the object's descriptor counter.
 * If the descriptor counter is 0, the object to which the descriptor points
 * is deallocated. Returns 0 iff no more expired object descriptors exist.
 */
int expire_object_descriptor_if_exists(expired_descriptor_page_list_t *list) {

// check pre-conditions
#ifdef SCM_CHECK_CONDITIONS
    if (list == NULL) {
        printf("Expired descriptor page list is NULL but was expected to exist.\n");
        return 0;
    }
#endif

    object_header_t *expired_object = (object_header_t*) get_expired_memory(list);

    if (expired_object != NULL) {
        //decrement the descriptor counter of the expired object
        if (atomic_int_dec_and_test((int*) &expired_object->dc_or_region_id)) {
            //with the descriptor counter now zero run finalizer and free it
            int finalizer_result = run_finalizer(expired_object);

            if (finalizer_result != 0) {
#ifdef SCM_DEBUG
                printf("WARNING: finalizer returned %d.\n", finalizer_result);
                printf("WARNING: %lx is a leak.\n",
                       (unsigned long) PAYLOAD_OFFSET(expired_object));
#endif

                return 1; //do not free the object
            }

#ifdef SCM_DEBUG
            printf("Object FREE(%lx).\n",
                   (unsigned long) PAYLOAD_OFFSET(expired_object));
#endif

#ifdef SCM_RECORD_MEMORY_USAGE
            dec_overhead(sizeof(object_header_t));
            inc_freed_mem(__real_malloc_usable_size(expired_object));
#endif
            __real_free(expired_object);

            return 1;
        } else {
#ifdef SCM_DEBUG
            printf("Decrementing DC==%d.\n", expired_object->dc_or_region_id);
#endif
            return 1;
        }
    } else {
#ifdef SCM_DEBUG
        printf("No expired object found.\n");
#endif
        return 0;
    }
}
Пример #12
0
inline void out_proc(FILE* fp, void * proc)
{
	Dl_info info;
	char* demangled = NULL;

	if (proc == 0)
		fprintf(fp, "null\n");
	else if (!dladdr(proc, &info) || !info.dli_sname)
		fprintf(fp, "%p\n", proc);
	else if ((demangled = abi::__cxa_demangle(info.dli_sname, 0, 0, 0))) {
		fprintf(fp, "%s + %ld\n", demangled, (intptr_t)proc - (intptr_t)info.dli_saddr);
		__real_free(demangled);
	} else
		fprintf(fp, "%s + %ld\n", info.dli_sname, (intptr_t)proc - (intptr_t)info.dli_saddr);
}
Пример #13
0
void __wrap_free(void* ptr)
{
    if (ptr == nullptr) {
#ifdef DEBUG_MALLOC
        printf("MALLOC: %p free\n", ptr);
#endif
        return;
    }

    void* p = (char*)ptr-16;
    size_t s = *(size_t*)p;
    mem_usage -= s+16;
    allocs--;
#ifdef DEBUG_MALLOC
    printf("MALLOC: %p : %lld free\n", (char*)p+16, s);
#endif
    __real_free(p);
}
Пример #14
0
extern "C" void* wrap(realloc)(void* p, size_t sz)
{
	init_lib();

	fibjs::MemPool& mp = fibjs::MemPool::global();

	if (p == 0)
	{
		void* p1 = __real_malloc(FULL_SIZE(sz));

		if (p1) {
			memset(p1, 0, STUB_SIZE);
			mp.add(p1, sz);
		}

		return MEM_PTR(p1);
	}

	if (sz == 0)
	{
		void* p1 = STUB_PTR(p);

		if (p1)
			mp.remove(p1);

		__real_free(p1);
		return 0;
	}

	void* p1 = STUB_PTR(p);

	mp.remove(p1);
	void* p2 = __real_realloc(p1, FULL_SIZE(sz));
	if (p2) {
		memset(p2, 0, STUB_SIZE);
		mp.add(p2, sz);
	}
	else
		mp.add(p1);

	return MEM_PTR(p2);
}
Пример #15
0
static inline void recycle_descriptor_page(descriptor_page_t *page) {

    if (descriptor_root->number_of_pooled_descriptor_pages <
            SCM_DESCRIPTOR_PAGE_FREELIST_SIZE) {

        descriptor_root->descriptor_page_pool[descriptor_root->number_of_pooled_descriptor_pages] = page;
    
        descriptor_root->number_of_pooled_descriptor_pages++;

#ifdef SCM_RECORD_MEMORY_USAGE
        inc_pooled_mem(sizeof(descriptor_page_t));
#endif
    } else {
#ifdef SCM_RECORD_MEMORY_USAGE
        dec_overhead(__real_malloc_usable_size(page));
        inc_freed_mem(__real_malloc_usable_size(page));
#endif

        __real_free(page);
    }
}
Пример #16
0
extern "C" NS_EXPORT jlong JNICALL
Java_org_mozilla_goanna_sqlite_SQLiteBridge_openDatabase(JNIEnv* jenv, jclass,
        jstring jDb)
{
    JNI_Setup(jenv);

    int rc;
    const char* dbPath;
    sqlite3 *db;
    char* errorMsg;

    dbPath = jenv->GetStringUTFChars(jDb, NULL);
    rc = f_sqlite3_open(dbPath, &db);
    jenv->ReleaseStringUTFChars(jDb, dbPath);
    if (rc != SQLITE_OK) {
        asprintf(&errorMsg, "Can't open database: %s\n", f_sqlite3_errmsg(db));
        LOG("Error in SQLiteBridge: %s\n", errorMsg);
        JNI_Throw(jenv, "org/mozilla/goanna/sqlite/SQLiteBridgeException", errorMsg);
        // errorMsg is allocated by asprintf, it needs to be freed by libc.
        __real_free(errorMsg);
    }
    return (jlong)db;
}
Пример #17
0
	void dump()
	{
		Item* items;
		Item* p;
		int32_t n = 0;
		int32_t i;
		char fname[32];

		init_lib();

		m_lock.lock();
		items = (Item*)__real_malloc(sizeof(Item) * m_list.count());

		p = m_list.head();
		while (p)
		{
			memcpy(items + n ++, p, sizeof(Item));
			p = m_list.next(p);
		}
		m_lock.unlock();

		caller root(0);
		for (i = 0; i < n; i ++)
			root.put(items[i].m_sz, items[i].m_frames, items[i].m_frame_count);

		sprintf(fname, "fibjs.%d.heap", getpid());
		FILE* fp = fopen(fname, "w");
		if (fp)
		{
			fprintf(fp, "\nfound %d times, total ", root.m_times);
			out_size(fp, root.m_sz);
			root.dumpSubs(fp);
			fclose(fp);
		}

		__real_free(items);
	}
Пример #18
0
static jobject
sqliteInternalCall(JNIEnv* jenv,
                   sqlite3 *db,
                   jstring jQuery,
                   jobjectArray jParams,
                   jlongArray jQueryRes)
{
    JNI_Setup(jenv);

    jobject jCursor = NULL;
    char* errorMsg;
    jsize numPars = 0;

    const char *pzTail;
    sqlite3_stmt *ppStmt;
    int rc;

    const char* queryStr;
    queryStr = jenv->GetStringUTFChars(jQuery, NULL);

    rc = f_sqlite3_prepare_v2(db, queryStr, -1, &ppStmt, &pzTail);
    if (rc != SQLITE_OK || ppStmt == NULL) {
        asprintf(&errorMsg, "Can't prepare statement: %s\n", f_sqlite3_errmsg(db));
        goto error_close;
    }
    jenv->ReleaseStringUTFChars(jQuery, queryStr);

    // Check if number of parameters matches
    if (jParams != NULL) {
        numPars = jenv->GetArrayLength(jParams);
    }
    int sqlNumPars;
    sqlNumPars = f_sqlite3_bind_parameter_count(ppStmt);
    if (numPars != sqlNumPars) {
        asprintf(&errorMsg, "Passed parameter count (%d) doesn't match SQL parameter count (%d)\n",
                 numPars, sqlNumPars);
        goto error_close;
    }

    if (jParams != NULL) {
        // Bind parameters, if any
        if (numPars > 0) {
            for (int i = 0; i < numPars; i++) {
                jobject jObjectParam = jenv->GetObjectArrayElement(jParams, i);
                // IsInstanceOf or isAssignableFrom? String is final, so IsInstanceOf
                // should be OK.
                jboolean isString = jenv->IsInstanceOf(jObjectParam, stringClass);
                if (isString != JNI_TRUE) {
                    asprintf(&errorMsg, "Parameter is not of String type");
                    goto error_close;
                }
                jstring jStringParam = (jstring)jObjectParam;
                const char* paramStr = jenv->GetStringUTFChars(jStringParam, NULL);
                // SQLite parameters index from 1.
                rc = f_sqlite3_bind_text(ppStmt, i + 1, paramStr, -1, SQLITE_TRANSIENT);
                jenv->ReleaseStringUTFChars(jStringParam, paramStr);
                if (rc != SQLITE_OK) {
                    asprintf(&errorMsg, "Error binding query parameter");
                    goto error_close;
                }
            }
        }
    }

    // Execute the query and step through the results
    rc = f_sqlite3_step(ppStmt);
    if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
        asprintf(&errorMsg, "Can't step statement: (%d) %s\n", rc, f_sqlite3_errmsg(db));
        goto error_close;
    }

    // Get the column count and names
    int cols;
    cols = f_sqlite3_column_count(ppStmt);

    {
        // Allocate a String[cols]
        jobjectArray jStringArray = jenv->NewObjectArray(cols,
                                    stringClass,
                                    NULL);
        if (jStringArray == NULL) {
            asprintf(&errorMsg, "Can't allocate String[]\n");
            goto error_close;
        }

        // Assign column names to the String[]
        for (int i = 0; i < cols; i++) {
            const char* colName = f_sqlite3_column_name(ppStmt, i);
            jstring jStr = jenv->NewStringUTF(colName);
            jenv->SetObjectArrayElement(jStringArray, i, jStr);
        }

        // Construct the MatrixCursor(String[]) with given column names
        jCursor = jenv->NewObject(cursorClass,
                                  jCursorConstructor,
                                  jStringArray);
        if (jCursor == NULL) {
            asprintf(&errorMsg, "Can't allocate MatrixBlobCursor\n");
            goto error_close;
        }
    }

    // Return the id and number of changed rows in jQueryRes
    {
        jlong id = f_sqlite3_last_insert_rowid(db);
        jenv->SetLongArrayRegion(jQueryRes, 0, 1, &id);

        jlong changed = f_sqlite3_changes(db);
        jenv->SetLongArrayRegion(jQueryRes, 1, 1, &changed);
    }

    // For each row, add an Object[] to the passed ArrayList,
    // with that containing either String or ByteArray objects
    // containing the columns
    while (rc != SQLITE_DONE) {
        // Process row
        // Construct Object[]
        jobjectArray jRow = jenv->NewObjectArray(cols,
                            objectClass,
                            NULL);
        if (jRow == NULL) {
            asprintf(&errorMsg, "Can't allocate jRow Object[]\n");
            goto error_close;
        }

        for (int i = 0; i < cols; i++) {
            int colType = f_sqlite3_column_type(ppStmt, i);
            if (colType == SQLITE_BLOB) {
                // Treat as blob
                const void* blob = f_sqlite3_column_blob(ppStmt, i);
                int colLen = f_sqlite3_column_bytes(ppStmt, i);

                // Construct ByteBuffer of correct size
                jobject jByteBuffer =
                    jenv->CallStaticObjectMethod(byteBufferClass,
                                                 jByteBufferAllocateDirect,
                                                 colLen);
                if (jByteBuffer == NULL) {
                    goto error_close;
                }

                // Get its backing array
                void* bufferArray = jenv->GetDirectBufferAddress(jByteBuffer);
                if (bufferArray == NULL) {
                    asprintf(&errorMsg, "Failure calling GetDirectBufferAddress\n");
                    goto error_close;
                }
                memcpy(bufferArray, blob, colLen);

                jenv->SetObjectArrayElement(jRow, i, jByteBuffer);
                jenv->DeleteLocalRef(jByteBuffer);
            } else if (colType == SQLITE_NULL) {
                jenv->SetObjectArrayElement(jRow, i, NULL);
            } else {
                // Treat everything else as text
                const char* txt = (const char*)f_sqlite3_column_text(ppStmt, i);
                jstring jStr = jenv->NewStringUTF(txt);
                jenv->SetObjectArrayElement(jRow, i, jStr);
                jenv->DeleteLocalRef(jStr);
            }
        }

        // Append Object[] to Cursor
        jenv->CallVoidMethod(jCursor, jCursorAddRow, jRow);

        // Clean up
        jenv->DeleteLocalRef(jRow);

        // Get next row
        rc = f_sqlite3_step(ppStmt);
        // Real error?
        if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
            asprintf(&errorMsg, "Can't re-step statement:(%d) %s\n", rc, f_sqlite3_errmsg(db));
            goto error_close;
        }
    }

    rc = f_sqlite3_finalize(ppStmt);
    if (rc != SQLITE_OK) {
        asprintf(&errorMsg, "Can't finalize statement: %s\n", f_sqlite3_errmsg(db));
        goto error_close;
    }

    return jCursor;

error_close:
    LOG("Error in SQLiteBridge: %s\n", errorMsg);
    JNI_Throw(jenv, "org/mozilla/goanna/sqlite/SQLiteBridgeException", errorMsg);
    // errorMsg is allocated by asprintf, it needs to be freed by libc.
    __real_free(errorMsg);
    return jCursor;
}
Пример #19
0
/* This function wraps the real free */
void * __wrap_free (void *data)
{
	void *lptr = __real_free(data);
	printf("free: %p\n", data);
	return lptr;
}
Пример #20
0
void MEM1_free(void *p)
{
	__real_free(p);
}
Пример #21
0
void __wrap_free(void *ptr)
{
	assert_nrt();
	__real_free(ptr);
}
Пример #22
0
extern "C" void __wrap_free(void* ptr)
{
    if (!isChunkInUse(ptr))
        __debugbreak();
    __real_free(ptr);
}
Пример #23
0
extern "C" void __wrap_free(void* ptr)
{
    breakOnHeapOpFromInterruptHandler();
    __real_free(ptr);
}
Пример #24
0
/**
 * Recycles a region in O(1) by pooling
 * the list of free region_pages except the
 * first region page iff the region_page_pool
 * limit is not exceeded, otherwise the region_pages
 * except the first one are deallocated and
 * the memory is handed back to the OS in O(n),
 * n = amount of region pages - 1.
 *
 * The remaining first region page indicates that the region
 * once existed, which is necessary to differentiate
 * it from regions which have not yet been used.
 * This indicates how many not-yet-used regions
 * are available.
 *
 * If the region was unregistered, all region pages
 * are recycled or deallocated.
 *
 * Returns if no or just one region_page
 * has been allocated in the region.
 */
static void recycle_region(region_t* region) {

#ifdef SCM_DEBUG
    printf("Recycle region: %p.\n", region);
#endif

// check pre-conditions
#ifdef SCM_CHECK_CONDITIONS
    if (region == NULL) {
        printf("Region recycling failed: NULL region should not appear in the descriptor buffers.\n");
        exit(-1);
    } else if (region->firstPage == NULL || region->lastPage == NULL) {
        printf("Region recycling failed: Descriptor points to a region which was not correctly initialized.\n");
        exit(-1);
    }
    if (region->dc != 0) {
        printf("Region recycling failed: Region seems to be still alive.\n");
        exit(-1);
    }
    region_t* invar_region = region;
#endif

    region_page_t* legacy_pages;
    unsigned long number_of_recycle_region_pages;

    // if the region has been used in the current thread...
    if (region->age == descriptor_root->current_time) {
        //.. recycle everything except the first page
        region_page_t* firstPage = region->firstPage;
        legacy_pages = firstPage->nextPage;

        memset(firstPage, '\0', SCM_REGION_PAGE_SIZE);
        region->last_address_in_last_page =
                firstPage->memory + SCM_REGION_PAGE_PAYLOAD_SIZE;

        // nothing to put into the pool
        if (legacy_pages == NULL) {

// check post-conditions
#ifdef SCM_CHECK_CONDITIONS
            if (region->number_of_region_pages != 1) {
                printf("Region recycling failed: Number of region pages is %u but only one region page exists.\n", region->number_of_region_pages);
                exit(-1);
            } else {
                if (region->firstPage != region->lastPage) {
                    printf("Region recycling failed: Last region page is not equal to first region page but only one region page exists.\n");
                    exit(-1);
                }
                if (region != invar_region) {
                    printf("Region recycling failed: The region changed during recycling.\n");
                    exit(-1);
                }
                if(region->firstPage->nextPage != NULL) {
                    printf("Region recycling failed: Next page pointer is corrupt: %p.\n", region->firstPage->nextPage);
                    exit(-1);
                }
            }
#endif
            region->dc = 0;

            return;
        }

// check post-conditions
#ifdef SCM_CHECK_CONDITIONS
        if (region->number_of_region_pages <= 1) {
            printf("Region recycling failed: Number of region pages is %u but more than 1 region pages were expected.\n", region->number_of_region_pages);
            exit(-1);
        }
#endif

        number_of_recycle_region_pages =
            region->number_of_region_pages - 1;

    }
    // if the region was a zombie in the current thread...
    else {
#ifdef SCM_DEBUG
        printf("Region expired.\n");
#endif
        //.. recycle everything, also the first page
        legacy_pages = region->firstPage;

        // nothing to put into the pool
        if (legacy_pages == NULL) {

// check post-conditions
#ifdef SCM_CHECK_CONDITIONS
            if (region->number_of_region_pages != 0) {
                printf("Region recycling failed: Number of region pages is not zero but no region pages exist.\n");
                exit(-1);
            } else {
                if (region->firstPage != region->lastPage) {
                    printf("Region recycling failed: Last region page is not equal to first region page but only one region page exists.\n");
                    exit(-1);
                }
                if (region != invar_region) {
                    printf("Region recycling failed: The region changed during recycling.\n");
                    exit(-1);
                }
            }
#endif
            region->dc = 0;

            return;
        }

// check post-conditions
#ifdef SCM_CHECK_CONDITIONS
        if (region->number_of_region_pages == 0) {
            printf("Region recycling failed: Number of region pages is %u but legacy pages could be obtained.\n", region->number_of_region_pages);
            exit(-1);
        }
#endif

        // a zombie region recycles all region pages
        number_of_recycle_region_pages =
            region->number_of_region_pages;
    }

    unsigned long number_of_pooled_region_pages =
        descriptor_root->number_of_pooled_region_pages;

    // is there space in the region page pool?
    if ((number_of_pooled_region_pages
            + number_of_recycle_region_pages) <=
            SCM_REGION_PAGE_FREELIST_SIZE) {
        //..yes, there is space in the region page pool

#ifdef SCM_RECORD_MEMORY_USAGE
        region_page_t* p = legacy_pages;

        while(p != NULL) {
            inc_pooled_mem(SCM_REGION_PAGE_SIZE);
            inc_overhead(__real_malloc_usable_size(p));

            p = p->nextPage;
        }
#endif

        region_page_t* first_in_pool = descriptor_root->region_page_pool;
        region_page_t* last_page = region->lastPage;

        last_page->nextPage = first_in_pool;
        descriptor_root->region_page_pool = legacy_pages;
        descriptor_root->number_of_pooled_region_pages =
            number_of_pooled_region_pages + number_of_recycle_region_pages;

    } else {

        //..no, there is no space in the region page pool
        // If the first region page is not NULL,
        // deallocate all region pages
        region_page_t* page2free = legacy_pages;

        while (page2free != NULL && (number_of_pooled_region_pages
                + number_of_recycle_region_pages) >
                SCM_REGION_PAGE_FREELIST_SIZE) {
            region_page_t* next = page2free->nextPage;
            __real_free(page2free);

#ifdef SCM_RECORD_MEMORY_USAGE
            inc_freed_mem(SCM_REGION_PAGE_SIZE);
#endif

            page2free = next;

            number_of_recycle_region_pages--;
        }


        // check again if we can recycle now
        if (page2free != NULL && (number_of_pooled_region_pages
                + number_of_recycle_region_pages) <=
                SCM_REGION_PAGE_FREELIST_SIZE) {
            
            region_page_t* first_in_pool = descriptor_root->region_page_pool;
            region_page_t* last_page = region->lastPage;
            if(last_page != NULL) {
                last_page->nextPage = first_in_pool;
                descriptor_root->region_page_pool = page2free;
                descriptor_root->number_of_pooled_region_pages =
                        number_of_recycle_region_pages - 1;

#ifdef SCM_RECORD_MEMORY_USAGE
                inc_pooled_mem(number_of_recycle_region_pages * SCM_REGION_PAGE_SIZE);
#endif
            }
        }

        descriptor_root->number_of_pooled_region_pages =
                number_of_pooled_region_pages + number_of_recycle_region_pages;
    }

    region->number_of_region_pages = 1;
    region->lastPage = region->firstPage;
    region->last_address_in_last_page =
            region->lastPage->memory + SCM_REGION_PAGE_PAYLOAD_SIZE;
    region->next_free_address = region->lastPage->memory;

// check post-conditions
#ifdef SCM_CHECK_CONDITIONS
        if (region->number_of_region_pages != 1) {
            printf("Region recycling failed: Number of region pages is %u but only one region page exists.\n", region->number_of_region_pages);
            exit(-1);
        } else {
            if (region->firstPage != region->lastPage) {
                printf("Region recycling failed: Last region page is not equal to first region page but only one region page should exist.\n");
                exit(-1);
            }
            if (region != invar_region) {
                printf("Region recycling failed: The region changed during recycling.\n");
                exit(-1);
            }
        }
#endif
    if (region->age != descriptor_root->current_time) {

        region->number_of_region_pages = 0;
        region->lastPage = region->firstPage = NULL;

// check post-conditions
#ifdef SCM_CHECK_CONDITIONS
        if (region->number_of_region_pages != 0) {
            printf("Region recycling failed: Number of region pages is %u but no region pages should exist.\n", region->number_of_region_pages);
            exit(-1);
        } else {
            if (region->firstPage != NULL) {
                printf("Region recycling failed: First page is not null as expected.\n");
                exit(-1);
            }
            if (region != invar_region) {
                printf("Region recycling failed: The region changed during recycling.\n");
                exit(-1);
            }
        }
#endif
    }
}