static void doMemRealloc(RTTEST hTest) { RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "%u reallocation, grow by 1 bytes\n", PAGE_SIZE * 2); size_t cbAlloc = RTRandS32Ex(1, _16K); void *pvBuf = NULL; RTTESTI_CHECK_RC_OK_RETV(RTMemSaferAllocZEx(&pvBuf, cbAlloc, 0)); for (uint32_t i = 0; i <= PAGE_SIZE * 2; i++) { cbAlloc += 1; RTTESTI_CHECK_RC_OK_RETV(RTMemSaferReallocZEx(cbAlloc - 1, pvBuf, cbAlloc, &pvBuf, 0)); memset(pvBuf, i & 0x7f, cbAlloc); } RTMemSaferFree(pvBuf, cbAlloc); RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "100 random reallocations\n"); uint8_t chFiller = 0x42; cbAlloc = 0; pvBuf = NULL; for (uint32_t i = 1; i <= 100; i++) { uint32_t cbNew = RTRandS32Ex(1, _16K + (i / 4) * _16K); RTTESTI_CHECK_RC_OK_RETV(RTMemSaferReallocZEx(cbAlloc, pvBuf, cbNew, &pvBuf, 0)); RTTESTI_CHECK(ASMMemIsAll8(pvBuf, RT_MIN(cbAlloc, cbNew), chFiller) == NULL); chFiller += 0x31; memset(pvBuf, chFiller, cbNew); cbAlloc = cbNew; } RTTESTI_CHECK_RC_OK_RETV(RTMemSaferReallocZEx(cbAlloc, pvBuf, 0, &pvBuf, 0)); RTTESTI_CHECK(pvBuf == NULL); }
/** Constructor for tst2. */ static DECLCALLBACK(int) tst2Ctor(RTMEMCACHE hMemCache, void *pvObj, void *pvUser) { RTTESTI_CHECK(hMemCache == g_hMemCache); RTTESTI_CHECK(ASMMemIsAll8(pvObj, 256, 0) == NULL); if (*(bool *)pvUser) return VERR_RESOURCE_BUSY; strcat((char *)pvObj, "ctor was called\n"); return VINF_SUCCESS; }
/** * Basic API checks. * We'll return if any of these fails. */ static void tst1(void) { RTTestISub("Basics"); char *psz; int rc = VINF_SUCCESS; /* RTStrAlloc */ RTTESTI_CHECK(psz = RTStrAlloc(0)); RTTESTI_CHECK(psz && !*psz); RTStrFree(psz); RTTESTI_CHECK(psz = RTStrAlloc(1)); RTTESTI_CHECK(psz && !*psz); RTStrFree(psz); RTTESTI_CHECK(psz = RTStrAlloc(128)); RTTESTI_CHECK(psz && !*psz); RTStrFree(psz); /* RTStrAllocEx */ psz = (char*)"asdfasdf"; RTTESTI_CHECK_RC(RTStrAllocEx(&psz, 0), VINF_SUCCESS); RTTESTI_CHECK(psz && !*psz); RTStrFree(psz); RTTESTI_CHECK_RC(RTStrAllocEx(&psz, 1), VINF_SUCCESS); RTTESTI_CHECK(psz && !*psz); RTStrFree(psz); RTTESTI_CHECK_RC(RTStrAllocEx(&psz, 128), VINF_SUCCESS); RTTESTI_CHECK(psz && !*psz); RTStrFree(psz); /* RTStrRealloc */ psz = NULL; RTTESTI_CHECK_RC(RTStrRealloc(&psz, 10), VINF_SUCCESS); RTTESTI_CHECK(psz && !psz[0]); RTTESTI_CHECK(psz && !psz[9]); RTStrFree(psz); psz = NULL; RTTESTI_CHECK_RC(RTStrRealloc(&psz, 0), VINF_SUCCESS); RTTESTI_CHECK(!psz); psz = NULL; RTTESTI_CHECK_RC(RTStrRealloc(&psz, 128), VINF_SUCCESS); RTTESTI_CHECK(psz && !psz[0]); RTTESTI_CHECK(psz && !psz[127]); if (psz) { memset(psz, 'a', 127); RTTESTI_CHECK_RC(rc = RTStrRealloc(&psz, 160), VINF_SUCCESS); if (RT_SUCCESS(rc) && psz) { RTTESTI_CHECK(!psz[127]); RTTESTI_CHECK(!psz[159]); RTTESTI_CHECK(ASMMemIsAll8(psz, 127, 'a') == NULL); memset(psz, 'b', 159); RTTESTI_CHECK_RC(rc = RTStrRealloc(&psz, 79), VINF_SUCCESS); if (RT_SUCCESS(rc)) { RTTESTI_CHECK(!psz[78]); RTTESTI_CHECK(ASMMemIsAll8(psz, 78, 'b') == NULL); RTTESTI_CHECK_RC(rc = RTStrRealloc(&psz, 0), VINF_SUCCESS); RTTESTI_CHECK(!psz); } } } RTStrFree(psz); /* RTStrDup */ RTTESTI_CHECK(psz = RTStrDup("")); RTTESTI_CHECK(psz && *psz == '\0'); RTStrFree(psz); RTTESTI_CHECK(psz = RTStrDup("abcdefghijklmnop")); RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklmnop")); RTStrFree(psz); /* RTStrDupEx */ psz = NULL; RTTESTI_CHECK_RC(RTStrDupEx(&psz, ""), VINF_SUCCESS); RTTESTI_CHECK(RT_FAILURE(rc) || *psz == '\0'); if (RT_SUCCESS(rc)) RTStrFree(psz); psz = (char*)"asdfasdfasdfasdf"; RTTESTI_CHECK_RC(rc = RTStrDupEx(&psz, "abcdefghijklmnop"), VINF_SUCCESS); RTTESTI_CHECK(RT_FAILURE(rc) || !RTStrCmp(psz, "abcdefghijklmnop")); if (RT_SUCCESS(rc)) RTStrFree(psz); /* RTStrDupN */ RTTESTI_CHECK(psz = RTStrDupN("abcdefg", 3)); RTTESTI_CHECK(!RTStrCmp(psz, "abc")); RTStrFree(psz); RTTESTI_CHECK(psz = RTStrDupN("abc", 100000)); RTTESTI_CHECK(!RTStrCmp(psz, "abc")); RTStrFree(psz); RTTESTI_CHECK(psz = RTStrDupN("abc", 0)); RTTESTI_CHECK(psz && *psz == '\0'); RTStrFree(psz); /* RTStrAAppend */ RTTESTI_CHECK(psz = RTStrDup("abc")); RTTESTI_CHECK_RC(RTStrAAppend(&psz, "def"), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abcdef")); RTStrFree(psz); RTTESTI_CHECK(psz = RTStrDup("abc")); RTTESTI_CHECK_RC(RTStrAAppend(&psz, ""), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abc")); RTTESTI_CHECK_RC(RTStrAAppend(&psz, NULL), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abc")); RTStrFree(psz); psz = NULL; RTTESTI_CHECK_RC(RTStrAAppend(&psz, "xyz"), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "xyz")); RTStrFree(psz); /* RTStrAAppendN */ RTTESTI_CHECK(psz = RTStrDup("abc")); RTTESTI_CHECK_RC(RTStrAAppendN(&psz, "def", 1), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abcd")); RTStrFree(psz); RTTESTI_CHECK(psz = RTStrDup("abc")); RTTESTI_CHECK_RC(RTStrAAppendN(&psz, "", 0), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abc")); RTTESTI_CHECK_RC(RTStrAAppendN(&psz, "", RTSTR_MAX), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abc")); RTTESTI_CHECK_RC(RTStrAAppendN(&psz, NULL, 0), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abc")); RTStrFree(psz); psz = NULL; RTTESTI_CHECK_RC(RTStrAAppendN(&psz, "abc", 2), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "ab")); RTTESTI_CHECK_RC(RTStrAAppendN(&psz, "cdefghijklm", 1), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abc")); RTTESTI_CHECK_RC(RTStrAAppendN(&psz, "defghijklm", RTSTR_MAX), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklm")); RTStrFree(psz); /* RTStrAAppendExN / RTStrAAppendExNV */ psz = NULL; RTTESTI_CHECK_RC(RTStrAAppendExN(&psz, 5, "a", (size_t)1, "bc", (size_t)1, "cdefg", RTSTR_MAX, "hijkl", (size_t)2, "jklmnopqrstuvwxyz", RTSTR_MAX), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklmnopqrstuvwxyz")); RTTESTI_CHECK_RC(RTStrAAppendExN(&psz, 0), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklmnopqrstuvwxyz")); RTTESTI_CHECK_RC(RTStrAAppendExN(&psz, 2, NULL, (size_t)0, "", (size_t)0), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklmnopqrstuvwxyz")); RTTESTI_CHECK_RC(RTStrAAppendExN(&psz, 1, "-", (size_t)1), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklmnopqrstuvwxyz-")); RTStrFree(psz); /* RTStrATruncate */ psz = NULL; RTTESTI_CHECK_RC(RTStrATruncate(&psz, 0), VINF_SUCCESS); RTTESTI_CHECK(!psz); RTTESTI_CHECK(psz = RTStrDup("")); RTTESTI_CHECK_RC(RTStrATruncate(&psz, 0), VINF_SUCCESS); RTStrFree(psz); RTTESTI_CHECK(psz = RTStrDup("1234567890")); RTTESTI_CHECK_RC(RTStrATruncate(&psz, 5), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "12345")); RTStrFree(psz); psz = NULL; for (uint32_t i = 0; i < 128; i++) RTTESTI_CHECK_RC_RETV(RTStrAAppend(&psz, "abcdefghijklmnopqrstuvwxyz"), VINF_SUCCESS); RTTESTI_CHECK_RC(RTStrATruncate(&psz, sizeof("abcdefghijklmnopqrstuvwxyz") - 1), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abcdefghijklmnopqrstuvwxyz")); RTTESTI_CHECK_RC(RTStrATruncate(&psz, 6), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "abcdef")); RTTESTI_CHECK_RC(RTStrATruncate(&psz, 1), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "a")); RTTESTI_CHECK_RC(RTStrATruncate(&psz, 0), VINF_SUCCESS); RTTESTI_CHECK(!RTStrCmp(psz, "")); RTStrFree(psz); }
/** * Basic API checks. * We'll return if any of these fails. */ static void tst1(RTMEMPOOL hMemPool) { void *pv; /* Normal alloc. */ RTTESTI_CHECK_RETV(pv = RTMemPoolAlloc(hMemPool, 1)); RTTESTI_CHECK_RETV(RTMemPoolRelease(hMemPool, pv) == 0); RTTESTI_CHECK_RETV(pv = RTMemPoolAlloc(hMemPool, 0)); RTTESTI_CHECK_RETV(RTMemPoolRelease(hMemPool, pv) == 0); /* Zeroed allocation. */ for (uint32_t i = 0; i < 512; i++) { RTTESTI_CHECK_RETV(pv = RTMemPoolAllocZ(hMemPool, 1024)); RTTESTI_CHECK(ASMMemIsAllU32(pv, 1024, 0) == NULL); memset(pv, 'a', 1024); RTTESTI_CHECK_RETV(RTMemPoolRefCount(pv) == 1); RTTESTI_CHECK_RETV(RTMemPoolRelease(hMemPool, pv) == 0); } RTTESTI_CHECK_RETV(pv = RTMemPoolAllocZ(hMemPool, 0)); RTTESTI_CHECK_RETV(RTMemPoolRelease(hMemPool, pv) == 0); /* Duped allocation. */ static const char szTest[] = "test string abcdef"; RTTESTI_CHECK_RETV(pv = RTMemPoolDup(hMemPool, szTest, sizeof(szTest))); RTTESTI_CHECK(memcmp(pv, szTest, sizeof(szTest)) == 0); RTTESTI_CHECK_RETV(RTMemPoolRelease(hMemPool, pv) == 0); for (uint32_t i = 0; i < 512; i++) { size_t const cb = 256 - sizeof(szTest); RTTESTI_CHECK_RETV(pv = RTMemPoolDupEx(hMemPool, szTest, sizeof(szTest), cb)); RTTESTI_CHECK(memcmp(pv, szTest, sizeof(szTest)) == 0); RTTESTI_CHECK(ASMMemIsAll8((uint8_t *)pv + sizeof(szTest), cb, 0) == NULL); memset(pv, 'b', sizeof(szTest) + cb); RTTESTI_CHECK_RETV(RTMemPoolRefCount(pv) == 1); RTTESTI_CHECK_RETV(RTMemPoolRelease(hMemPool, pv) == 0); } /* Reallocation */ RTTESTI_CHECK_RETV(pv = RTMemPoolRealloc(hMemPool, NULL, 1)); RTTESTI_CHECK_RETV(pv = RTMemPoolRealloc(hMemPool, pv, 2)); RTTESTI_CHECK_RETV(RTMemPoolRelease(hMemPool, pv) == 0); RTTESTI_CHECK_RETV(pv = RTMemPoolAlloc(hMemPool, 42)); RTTESTI_CHECK_RETV(pv = RTMemPoolRealloc(hMemPool, pv, 32)); RTTESTI_CHECK_RETV(RTMemPoolRelease(hMemPool, pv) == 0); RTTESTI_CHECK_RETV(pv = RTMemPoolRealloc(hMemPool, NULL, 128)); RTTESTI_CHECK_RETV(pv = RTMemPoolRealloc(hMemPool, pv, 256)); RTTESTI_CHECK_RETV(RTMemPoolRealloc(hMemPool, pv, 0) == NULL); /* Free (a bit hard to test) */ RTMemPoolFree(hMemPool, NULL); RTMemPoolFree(hMemPool, RTMemPoolAlloc(hMemPool, 42)); /* Memory referencing. */ for (uint32_t i = 1; i <= 4096; i *= 3) { void *pv2; RTTESTI_CHECK_RETV(pv = RTMemPoolAlloc(hMemPool, i)); RTTESTI_CHECK(RTMemPoolRefCount(pv) == 1); memset(pv, 'a', i); RTTESTI_CHECK_MSG_RETV((pv2 = ASMMemIsAll8(pv, i, 'a')) == NULL, ("i=%#x pv=%p off=%#x\n", i, pv, (uintptr_t)pv2 - (uintptr_t)pv)); RTTESTI_CHECK(RTMemPoolRetain(pv) == 2); RTTESTI_CHECK(RTMemPoolRefCount(pv) == 2); RTTESTI_CHECK(RTMemPoolRetain(pv) == 3); RTTESTI_CHECK(RTMemPoolRefCount(pv) == 3); RTTESTI_CHECK(RTMemPoolRetain(pv) == 4); RTTESTI_CHECK(RTMemPoolRefCount(pv) == 4); RTTESTI_CHECK_MSG_RETV((pv2 = ASMMemIsAll8(pv, i, 'a')) == NULL, ("i=%#x pv=%p off=%#x\n", i, pv, (uintptr_t)pv2 - (uintptr_t)pv)); RTTESTI_CHECK(RTMemPoolRelease(hMemPool, pv) == 3); RTTESTI_CHECK(RTMemPoolRefCount(pv) == 3); RTTESTI_CHECK_MSG_RETV((pv2 = ASMMemIsAll8(pv, i, 'a')) == NULL, ("i=%#x pv=%p off=%#x\n", i, pv, (uintptr_t)pv2 - (uintptr_t)pv)); RTTESTI_CHECK(RTMemPoolRetain(pv) == 4); RTTESTI_CHECK(RTMemPoolRefCount(pv) == 4); RTTESTI_CHECK(RTMemPoolRetain(pv) == 5); RTTESTI_CHECK(RTMemPoolRefCount(pv) == 5); RTTESTI_CHECK(RTMemPoolRetain(pv) == 6); RTTESTI_CHECK(RTMemPoolRefCount(pv) == 6); RTTESTI_CHECK(RTMemPoolRelease(NIL_RTMEMPOOL, pv) == 5); RTTESTI_CHECK(RTMemPoolRelease(NIL_RTMEMPOOL, pv) == 4); RTTESTI_CHECK_MSG_RETV((pv2 = ASMMemIsAll8(pv, i, 'a')) == NULL, ("i=%#x pv=%p off=%#x\n", i, pv, (uintptr_t)pv2 - (uintptr_t)pv)); for (uint32_t cRefs = 3;; cRefs--) { RTTESTI_CHECK(RTMemPoolRelease(hMemPool, pv) == cRefs); if (cRefs == 0) break; RTTESTI_CHECK(RTMemPoolRefCount(pv) == cRefs); RTTESTI_CHECK_MSG_RETV((pv2 = ASMMemIsAll8(pv, i, 'a')) == NULL, ("i=%#x pv=%p off=%#x cRefs=%d\n", i, pv, (uintptr_t)pv2 - (uintptr_t)pv, cRefs)); for (uint32_t j = 0; j < 42; j++) { RTTESTI_CHECK_RETV(pv2 = RTMemPoolAlloc(hMemPool, i)); RTTESTI_CHECK_RETV(pv2 != pv); memset(pv2, 'f', i); RTTESTI_CHECK(RTMemPoolRelease(hMemPool, pv2) == 0); RTTESTI_CHECK_MSG_RETV((pv2 = ASMMemIsAll8(pv, i, 'a')) == NULL, ("i=%#x pv=%p off=%#x cRefs=%d\n", i, pv, (uintptr_t)pv2 - (uintptr_t)pv, cRefs)); } } } }
/** * Internal free. */ RTDECL(void) rtR3MemFree(const char *pszOp, RTMEMTYPE enmType, void *pv, void *pvCaller, RT_SRC_POS_DECL) { /* * Simple case. */ if (!pv) return; /* * Check watch points. */ for (unsigned i = 0; i < RT_ELEMENTS(gapvRTMemFreeWatch); i++) if (gapvRTMemFreeWatch[i] == pv) RTAssertDoPanic(); #ifdef RTALLOC_EFENCE_TRACE /* * Find the block. */ PRTMEMBLOCK pBlock = rtmemBlockRemove(pv); if (pBlock) { if (gfRTMemFreeLog) RTLogPrintf("RTMem %s: pv=%p pvCaller=%p cbUnaligned=%#x\n", pszOp, pv, pvCaller, pBlock->cbUnaligned); # ifdef RTALLOC_EFENCE_NOMAN_FILLER /* * Check whether the no man's land is untouched. */ # ifdef RTALLOC_EFENCE_IN_FRONT void *pvWrong = ASMMemIsAll8((char *)pv + pBlock->cbUnaligned, RT_ALIGN_Z(pBlock->cbAligned, PAGE_SIZE) - pBlock->cbUnaligned, RTALLOC_EFENCE_NOMAN_FILLER); # else /* Alignment must match allocation alignment in rtMemAlloc(). */ void *pvWrong = ASMMemIsAll8((char *)pv + pBlock->cbUnaligned, pBlock->cbAligned - pBlock->cbUnaligned, RTALLOC_EFENCE_NOMAN_FILLER); if (pvWrong) RTAssertDoPanic(); pvWrong = ASMMemIsAll8((void *)((uintptr_t)pv & ~PAGE_OFFSET_MASK), RT_ALIGN_Z(pBlock->cbAligned, PAGE_SIZE) - pBlock->cbAligned, RTALLOC_EFENCE_NOMAN_FILLER); # endif if (pvWrong) RTAssertDoPanic(); # endif # ifdef RTALLOC_EFENCE_FREE_FILL /* * Fill the user part of the block. */ memset(pv, RTALLOC_EFENCE_FREE_FILL, pBlock->cbUnaligned); # endif # if defined(RTALLOC_EFENCE_FREE_DELAYED) && RTALLOC_EFENCE_FREE_DELAYED > 0 /* * We're doing delayed freeing. * That means we'll expand the E-fence to cover the entire block. */ int rc = RTMemProtect(pv, pBlock->cbAligned, RTMEM_PROT_NONE); if (RT_SUCCESS(rc)) { /* * Insert it into the free list and process pending frees. */ rtmemBlockDelayInsert(pBlock); while ((pBlock = rtmemBlockDelayRemove()) != NULL) { pv = pBlock->Core.Key; # ifdef RTALLOC_EFENCE_IN_FRONT void *pvBlock = (char *)pv - RTALLOC_EFENCE_SIZE; # else void *pvBlock = (void *)((uintptr_t)pv & ~PAGE_OFFSET_MASK); # endif size_t cbBlock = RT_ALIGN_Z(pBlock->cbAligned, PAGE_SIZE) + RTALLOC_EFENCE_SIZE; rc = RTMemProtect(pvBlock, cbBlock, RTMEM_PROT_READ | RTMEM_PROT_WRITE); if (RT_SUCCESS(rc)) RTMemPageFree(pvBlock, RT_ALIGN_Z(pBlock->cbAligned, PAGE_SIZE) + RTALLOC_EFENCE_SIZE); else rtmemComplain(pszOp, "RTMemProtect(%p, %#x, RTMEM_PROT_READ | RTMEM_PROT_WRITE) -> %d\n", pvBlock, cbBlock, rc); rtmemBlockFree(pBlock); } } else rtmemComplain(pszOp, "Failed to expand the efence of pv=%p cb=%d, rc=%d.\n", pv, pBlock, rc); # else /* !RTALLOC_EFENCE_FREE_DELAYED */ /* * Turn of the E-fence and free it. */ # ifdef RTALLOC_EFENCE_IN_FRONT void *pvBlock = (char *)pv - RTALLOC_EFENCE_SIZE; void *pvEFence = pvBlock; # else void *pvBlock = (void *)((uintptr_t)pv & ~PAGE_OFFSET_MASK); void *pvEFence = (char *)pv + pBlock->cb; # endif int rc = RTMemProtect(pvEFence, RTALLOC_EFENCE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE); if (RT_SUCCESS(rc)) RTMemPageFree(pvBlock, RT_ALIGN_Z(pBlock->cbAligned, PAGE_SIZE) + RTALLOC_EFENCE_SIZE); else rtmemComplain(pszOp, "RTMemProtect(%p, %#x, RTMEM_PROT_READ | RTMEM_PROT_WRITE) -> %d\n", pvEFence, RTALLOC_EFENCE_SIZE, rc); rtmemBlockFree(pBlock); # endif /* !RTALLOC_EFENCE_FREE_DELAYED */ } else rtmemComplain(pszOp, "pv=%p not found! Incorrect free!\n", pv); #else /* !RTALLOC_EFENCE_TRACE */ /* * We have no size tracking, so we're not doing any freeing because * we cannot if the E-fence is after the block. * Let's just expand the E-fence to the first page of the user bit * since we know that it's around. */ int rc = RTMemProtect((void *)((uintptr_t)pv & ~PAGE_OFFSET_MASK), PAGE_SIZE, RTMEM_PROT_NONE); if (RT_FAILURE(rc)) rtmemComplain(pszOp, "RTMemProtect(%p, PAGE_SIZE, RTMEM_PROT_NONE) -> %d\n", (void *)((uintptr_t)pv & ~PAGE_OFFSET_MASK), rc); #endif /* !RTALLOC_EFENCE_TRACE */ }