Merge pull request #1795 from felixhandte/workspace-asan
Add Poisoned Redzones to the Workspace When Compiling with ASAN
This commit is contained in:
+44
-4
@@ -74,10 +74,50 @@ void __msan_poison(const volatile void *a, size_t size);
|
|||||||
intptr_t __msan_test_shadow(const volatile void *x, size_t size);
|
intptr_t __msan_test_shadow(const volatile void *x, size_t size);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined (MEMORY_SANITIZER)
|
/* detects whether we are being compiled under asan */
|
||||||
# define MEM_SKIP_MSAN __attribute__((no_sanitize("memory")))
|
#if defined (__has_feature)
|
||||||
#else
|
# if __has_feature(address_sanitizer)
|
||||||
# define MEM_SKIP_MSAN
|
# define ADDRESS_SANITIZER 1
|
||||||
|
# endif
|
||||||
|
#elif defined(__SANITIZE_ADDRESS__)
|
||||||
|
# define ADDRESS_SANITIZER 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined (ADDRESS_SANITIZER)
|
||||||
|
/* Not all platforms that support asan provide sanitizers/asan_interface.h.
|
||||||
|
* We therefore declare the functions we need ourselves, rather than trying to
|
||||||
|
* include the header file... */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks a memory region (<c>[addr, addr+size)</c>) as unaddressable.
|
||||||
|
*
|
||||||
|
* This memory must be previously allocated by your program. Instrumented
|
||||||
|
* code is forbidden from accessing addresses in this region until it is
|
||||||
|
* unpoisoned. This function is not guaranteed to poison the entire region -
|
||||||
|
* it could poison only a subregion of <c>[addr, addr+size)</c> due to ASan
|
||||||
|
* alignment restrictions.
|
||||||
|
*
|
||||||
|
* \note This function is not thread-safe because no two threads can poison or
|
||||||
|
* unpoison memory in the same memory region simultaneously.
|
||||||
|
*
|
||||||
|
* \param addr Start of memory region.
|
||||||
|
* \param size Size of memory region. */
|
||||||
|
void __asan_poison_memory_region(void const volatile *addr, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks a memory region (<c>[addr, addr+size)</c>) as addressable.
|
||||||
|
*
|
||||||
|
* This memory must be previously allocated by your program. Accessing
|
||||||
|
* addresses in this region is allowed until this region is poisoned again.
|
||||||
|
* This function could unpoison a super-region of <c>[addr, addr+size)</c> due
|
||||||
|
* to ASan alignment restrictions.
|
||||||
|
*
|
||||||
|
* \note This function is not thread-safe because no two threads can
|
||||||
|
* poison or unpoison memory in the same memory region simultaneously.
|
||||||
|
*
|
||||||
|
* \param addr Start of memory region.
|
||||||
|
* \param size Size of memory region. */
|
||||||
|
void __asan_unpoison_memory_region(void const volatile *addr, size_t size);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -130,15 +130,11 @@ static void ZSTD_freeCCtxContent(ZSTD_CCtx* cctx)
|
|||||||
{
|
{
|
||||||
assert(cctx != NULL);
|
assert(cctx != NULL);
|
||||||
assert(cctx->staticSize == 0);
|
assert(cctx->staticSize == 0);
|
||||||
/* Only free workspace if cctx not in workspace, otherwise the workspace
|
|
||||||
* will be freed when the cctx itself is freed. */
|
|
||||||
if ((void*)cctx->workspace.workspace != (void*)cctx) {
|
|
||||||
ZSTD_cwksp_free(&cctx->workspace, cctx->customMem);
|
|
||||||
}
|
|
||||||
ZSTD_clearAllDicts(cctx);
|
ZSTD_clearAllDicts(cctx);
|
||||||
#ifdef ZSTD_MULTITHREAD
|
#ifdef ZSTD_MULTITHREAD
|
||||||
ZSTDMT_freeCCtx(cctx->mtctx); cctx->mtctx = NULL;
|
ZSTDMT_freeCCtx(cctx->mtctx); cctx->mtctx = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
ZSTD_cwksp_free(&cctx->workspace, cctx->customMem);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
|
size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
|
||||||
@@ -146,8 +142,13 @@ size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
|
|||||||
if (cctx==NULL) return 0; /* support free on NULL */
|
if (cctx==NULL) return 0; /* support free on NULL */
|
||||||
RETURN_ERROR_IF(cctx->staticSize, memory_allocation,
|
RETURN_ERROR_IF(cctx->staticSize, memory_allocation,
|
||||||
"not compatible with static CCtx");
|
"not compatible with static CCtx");
|
||||||
ZSTD_freeCCtxContent(cctx);
|
{
|
||||||
ZSTD_free(cctx, cctx->customMem);
|
int cctxInWorkspace = ZSTD_cwksp_owns_buffer(&cctx->workspace, cctx);
|
||||||
|
ZSTD_freeCCtxContent(cctx);
|
||||||
|
if (!cctxInWorkspace) {
|
||||||
|
ZSTD_free(cctx, cctx->customMem);
|
||||||
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1077,10 +1078,19 @@ ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams,
|
|||||||
size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog);
|
size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog);
|
||||||
size_t const hSize = ((size_t)1) << cParams->hashLog;
|
size_t const hSize = ((size_t)1) << cParams->hashLog;
|
||||||
U32 const hashLog3 = (forCCtx && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0;
|
U32 const hashLog3 = (forCCtx && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0;
|
||||||
size_t const h3Size = ((size_t)1) << hashLog3;
|
size_t const h3Size = hashLog3 ? ((size_t)1) << hashLog3 : 0;
|
||||||
size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
|
/* We don't use ZSTD_cwksp_alloc_size() here because the tables aren't
|
||||||
size_t const optPotentialSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits)) * sizeof(U32)
|
* surrounded by redzones in ASAN. */
|
||||||
+ (ZSTD_OPT_NUM+1) * (sizeof(ZSTD_match_t)+sizeof(ZSTD_optimal_t));
|
size_t const tableSpace = chainSize * sizeof(U32)
|
||||||
|
+ hSize * sizeof(U32)
|
||||||
|
+ h3Size * sizeof(U32);
|
||||||
|
size_t const optPotentialSpace =
|
||||||
|
ZSTD_cwksp_alloc_size((MaxML+1) * sizeof(U32))
|
||||||
|
+ ZSTD_cwksp_alloc_size((MaxLL+1) * sizeof(U32))
|
||||||
|
+ ZSTD_cwksp_alloc_size((MaxOff+1) * sizeof(U32))
|
||||||
|
+ ZSTD_cwksp_alloc_size((1<<Litbits) * sizeof(U32))
|
||||||
|
+ ZSTD_cwksp_alloc_size((ZSTD_OPT_NUM+1) * sizeof(ZSTD_match_t))
|
||||||
|
+ ZSTD_cwksp_alloc_size((ZSTD_OPT_NUM+1) * sizeof(ZSTD_optimal_t));
|
||||||
size_t const optSpace = (forCCtx && (cParams->strategy >= ZSTD_btopt))
|
size_t const optSpace = (forCCtx && (cParams->strategy >= ZSTD_btopt))
|
||||||
? optPotentialSpace
|
? optPotentialSpace
|
||||||
: 0;
|
: 0;
|
||||||
@@ -1097,20 +1107,23 @@ size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params)
|
|||||||
size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
|
size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
|
||||||
U32 const divider = (cParams.minMatch==3) ? 3 : 4;
|
U32 const divider = (cParams.minMatch==3) ? 3 : 4;
|
||||||
size_t const maxNbSeq = blockSize / divider;
|
size_t const maxNbSeq = blockSize / divider;
|
||||||
size_t const tokenSpace = WILDCOPY_OVERLENGTH + blockSize + 11*maxNbSeq;
|
size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize)
|
||||||
size_t const entropySpace = HUF_WORKSPACE_SIZE;
|
+ ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(seqDef))
|
||||||
size_t const blockStateSpace = 2 * sizeof(ZSTD_compressedBlockState_t);
|
+ 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE));
|
||||||
|
size_t const entropySpace = ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE);
|
||||||
|
size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t));
|
||||||
size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 1);
|
size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 1);
|
||||||
|
|
||||||
size_t const ldmSpace = ZSTD_ldm_getTableSize(params->ldmParams);
|
size_t const ldmSpace = ZSTD_ldm_getTableSize(params->ldmParams);
|
||||||
size_t const ldmSeqSpace = ZSTD_ldm_getMaxNbSeq(params->ldmParams, blockSize) * sizeof(rawSeq);
|
size_t const ldmSeqSpace = ZSTD_cwksp_alloc_size(ZSTD_ldm_getMaxNbSeq(params->ldmParams, blockSize) * sizeof(rawSeq));
|
||||||
|
|
||||||
size_t const neededSpace = entropySpace + blockStateSpace + tokenSpace +
|
size_t const neededSpace = entropySpace + blockStateSpace + tokenSpace +
|
||||||
matchStateSize + ldmSpace + ldmSeqSpace;
|
matchStateSize + ldmSpace + ldmSeqSpace;
|
||||||
|
size_t const cctxSpace = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx));
|
||||||
|
|
||||||
DEBUGLOG(5, "sizeof(ZSTD_CCtx) : %u", (U32)sizeof(ZSTD_CCtx));
|
DEBUGLOG(5, "sizeof(ZSTD_CCtx) : %u", (U32)cctxSpace);
|
||||||
DEBUGLOG(5, "estimate workspace : %u", (U32)neededSpace);
|
DEBUGLOG(5, "estimate workspace : %u", (U32)neededSpace);
|
||||||
return sizeof(ZSTD_CCtx) + neededSpace;
|
return cctxSpace + neededSpace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1146,7 +1159,8 @@ size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params)
|
|||||||
size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
|
size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
|
||||||
size_t const inBuffSize = ((size_t)1 << cParams.windowLog) + blockSize;
|
size_t const inBuffSize = ((size_t)1 << cParams.windowLog) + blockSize;
|
||||||
size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1;
|
size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1;
|
||||||
size_t const streamingSize = inBuffSize + outBuffSize;
|
size_t const streamingSize = ZSTD_cwksp_alloc_size(inBuffSize)
|
||||||
|
+ ZSTD_cwksp_alloc_size(outBuffSize);
|
||||||
|
|
||||||
return CCtxSize + streamingSize;
|
return CCtxSize + streamingSize;
|
||||||
}
|
}
|
||||||
@@ -1393,7 +1407,9 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
|||||||
size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
|
size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
|
||||||
U32 const divider = (params.cParams.minMatch==3) ? 3 : 4;
|
U32 const divider = (params.cParams.minMatch==3) ? 3 : 4;
|
||||||
size_t const maxNbSeq = blockSize / divider;
|
size_t const maxNbSeq = blockSize / divider;
|
||||||
size_t const tokenSpace = WILDCOPY_OVERLENGTH + blockSize + 11*maxNbSeq;
|
size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize)
|
||||||
|
+ ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(seqDef))
|
||||||
|
+ 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE));
|
||||||
size_t const buffOutSize = (zbuff==ZSTDb_buffered) ? ZSTD_compressBound(blockSize)+1 : 0;
|
size_t const buffOutSize = (zbuff==ZSTDb_buffered) ? ZSTD_compressBound(blockSize)+1 : 0;
|
||||||
size_t const buffInSize = (zbuff==ZSTDb_buffered) ? windowSize + blockSize : 0;
|
size_t const buffInSize = (zbuff==ZSTDb_buffered) ? windowSize + blockSize : 0;
|
||||||
size_t const matchStateSize = ZSTD_sizeof_matchState(¶ms.cParams, /* forCCtx */ 1);
|
size_t const matchStateSize = ZSTD_sizeof_matchState(¶ms.cParams, /* forCCtx */ 1);
|
||||||
@@ -1408,12 +1424,12 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
|||||||
ZSTD_cwksp_bump_oversized_duration(ws, 0);
|
ZSTD_cwksp_bump_oversized_duration(ws, 0);
|
||||||
|
|
||||||
/* Check if workspace is large enough, alloc a new one if needed */
|
/* Check if workspace is large enough, alloc a new one if needed */
|
||||||
{ size_t const cctxSpace = zc->staticSize ? sizeof(ZSTD_CCtx) : 0;
|
{ size_t const cctxSpace = zc->staticSize ? ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx)) : 0;
|
||||||
size_t const entropySpace = HUF_WORKSPACE_SIZE;
|
size_t const entropySpace = ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE);
|
||||||
size_t const blockStateSpace = 2 * sizeof(ZSTD_compressedBlockState_t);
|
size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t));
|
||||||
size_t const bufferSpace = buffInSize + buffOutSize;
|
size_t const bufferSpace = ZSTD_cwksp_alloc_size(buffInSize) + ZSTD_cwksp_alloc_size(buffOutSize);
|
||||||
size_t const ldmSpace = ZSTD_ldm_getTableSize(params.ldmParams);
|
size_t const ldmSpace = ZSTD_ldm_getTableSize(params.ldmParams);
|
||||||
size_t const ldmSeqSpace = maxNbLdmSeq * sizeof(rawSeq);
|
size_t const ldmSeqSpace = ZSTD_cwksp_alloc_size(maxNbLdmSeq * sizeof(rawSeq));
|
||||||
|
|
||||||
size_t const neededSpace =
|
size_t const neededSpace =
|
||||||
cctxSpace +
|
cctxSpace +
|
||||||
@@ -1649,12 +1665,13 @@ static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx,
|
|||||||
/* copy tables */
|
/* copy tables */
|
||||||
{ size_t const chainSize = (cdict_cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cdict_cParams->chainLog);
|
{ size_t const chainSize = (cdict_cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cdict_cParams->chainLog);
|
||||||
size_t const hSize = (size_t)1 << cdict_cParams->hashLog;
|
size_t const hSize = (size_t)1 << cdict_cParams->hashLog;
|
||||||
size_t const tableSpace = (chainSize + hSize) * sizeof(U32);
|
|
||||||
assert((U32*)cctx->blockState.matchState.chainTable == (U32*)cctx->blockState.matchState.hashTable + hSize); /* chainTable must follow hashTable */
|
memcpy(cctx->blockState.matchState.hashTable,
|
||||||
assert((U32*)cctx->blockState.matchState.hashTable3 == (U32*)cctx->blockState.matchState.chainTable + chainSize);
|
cdict->matchState.hashTable,
|
||||||
assert((U32*)cdict->matchState.chainTable == (U32*)cdict->matchState.hashTable + hSize); /* chainTable must follow hashTable */
|
hSize * sizeof(U32));
|
||||||
assert((U32*)cdict->matchState.hashTable3 == (U32*)cdict->matchState.chainTable + chainSize);
|
memcpy(cctx->blockState.matchState.chainTable,
|
||||||
memcpy(cctx->blockState.matchState.hashTable, cdict->matchState.hashTable, tableSpace); /* presumes all tables follow each other */
|
cdict->matchState.chainTable,
|
||||||
|
chainSize * sizeof(U32));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Zero the hashTable3, since the cdict never fills it */
|
/* Zero the hashTable3, since the cdict never fills it */
|
||||||
@@ -1741,10 +1758,16 @@ static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
|
|||||||
size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog;
|
size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog;
|
||||||
int const h3log = srcCCtx->blockState.matchState.hashLog3;
|
int const h3log = srcCCtx->blockState.matchState.hashLog3;
|
||||||
size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0;
|
size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0;
|
||||||
size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
|
|
||||||
assert((U32*)dstCCtx->blockState.matchState.chainTable == (U32*)dstCCtx->blockState.matchState.hashTable + hSize); /* chainTable must follow hashTable */
|
memcpy(dstCCtx->blockState.matchState.hashTable,
|
||||||
assert((U32*)dstCCtx->blockState.matchState.hashTable3 == (U32*)dstCCtx->blockState.matchState.chainTable + chainSize);
|
srcCCtx->blockState.matchState.hashTable,
|
||||||
memcpy(dstCCtx->blockState.matchState.hashTable, srcCCtx->blockState.matchState.hashTable, tableSpace); /* presumes all tables follow each other */
|
hSize * sizeof(U32));
|
||||||
|
memcpy(dstCCtx->blockState.matchState.chainTable,
|
||||||
|
srcCCtx->blockState.matchState.chainTable,
|
||||||
|
chainSize * sizeof(U32));
|
||||||
|
memcpy(dstCCtx->blockState.matchState.hashTable3,
|
||||||
|
srcCCtx->blockState.matchState.hashTable3,
|
||||||
|
h3Size * sizeof(U32));
|
||||||
}
|
}
|
||||||
|
|
||||||
ZSTD_cwksp_mark_tables_clean(&dstCCtx->workspace);
|
ZSTD_cwksp_mark_tables_clean(&dstCCtx->workspace);
|
||||||
@@ -3127,8 +3150,11 @@ size_t ZSTD_estimateCDictSize_advanced(
|
|||||||
ZSTD_dictLoadMethod_e dictLoadMethod)
|
ZSTD_dictLoadMethod_e dictLoadMethod)
|
||||||
{
|
{
|
||||||
DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (unsigned)sizeof(ZSTD_CDict));
|
DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (unsigned)sizeof(ZSTD_CDict));
|
||||||
return sizeof(ZSTD_CDict) + HUF_WORKSPACE_SIZE + ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0)
|
return ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict))
|
||||||
+ (dictLoadMethod == ZSTD_dlm_byRef ? 0 : ZSTD_cwksp_align(dictSize, sizeof(void *)));
|
+ ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE)
|
||||||
|
+ ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0)
|
||||||
|
+ (dictLoadMethod == ZSTD_dlm_byRef ? 0
|
||||||
|
: ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void *))));
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel)
|
size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel)
|
||||||
@@ -3208,11 +3234,11 @@ ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize,
|
|||||||
if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
|
if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
|
||||||
|
|
||||||
{ size_t const workspaceSize =
|
{ size_t const workspaceSize =
|
||||||
sizeof(ZSTD_CDict) +
|
ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict)) +
|
||||||
HUF_WORKSPACE_SIZE +
|
ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE) +
|
||||||
ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0) +
|
ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0) +
|
||||||
(dictLoadMethod == ZSTD_dlm_byRef ? 0
|
(dictLoadMethod == ZSTD_dlm_byRef ? 0
|
||||||
: ZSTD_cwksp_align(dictSize, sizeof(void*)));
|
: ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*))));
|
||||||
void* const workspace = ZSTD_malloc(workspaceSize, customMem);
|
void* const workspace = ZSTD_malloc(workspaceSize, customMem);
|
||||||
ZSTD_cwksp ws;
|
ZSTD_cwksp ws;
|
||||||
ZSTD_CDict* cdict;
|
ZSTD_CDict* cdict;
|
||||||
@@ -3260,12 +3286,11 @@ size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
|
|||||||
{
|
{
|
||||||
if (cdict==NULL) return 0; /* support free on NULL */
|
if (cdict==NULL) return 0; /* support free on NULL */
|
||||||
{ ZSTD_customMem const cMem = cdict->customMem;
|
{ ZSTD_customMem const cMem = cdict->customMem;
|
||||||
/* Only free workspace if cdict not in workspace, otherwise the
|
int cdictInWorkspace = ZSTD_cwksp_owns_buffer(&cdict->workspace, cdict);
|
||||||
* workspace will be freed when the cdict itself is freed. */
|
ZSTD_cwksp_free(&cdict->workspace, cMem);
|
||||||
if ((void*)cdict->workspace.workspace != (void*)cdict) {
|
if (!cdictInWorkspace) {
|
||||||
ZSTD_cwksp_free(&cdict->workspace, cMem);
|
ZSTD_free(cdict, cMem);
|
||||||
}
|
}
|
||||||
ZSTD_free(cdict, cMem);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3291,8 +3316,11 @@ const ZSTD_CDict* ZSTD_initStaticCDict(
|
|||||||
ZSTD_compressionParameters cParams)
|
ZSTD_compressionParameters cParams)
|
||||||
{
|
{
|
||||||
size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0);
|
size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0);
|
||||||
size_t const neededSize = sizeof(ZSTD_CDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : ZSTD_cwksp_align(dictSize, sizeof(void*)))
|
size_t const neededSize = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict))
|
||||||
+ HUF_WORKSPACE_SIZE + matchStateSize;
|
+ (dictLoadMethod == ZSTD_dlm_byRef ? 0
|
||||||
|
: ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*))))
|
||||||
|
+ ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE)
|
||||||
|
+ matchStateSize;
|
||||||
ZSTD_CDict* cdict;
|
ZSTD_CDict* cdict;
|
||||||
|
|
||||||
if ((size_t)workspace & 7) return NULL; /* 8-aligned */
|
if ((size_t)workspace & 7) return NULL; /* 8-aligned */
|
||||||
|
|||||||
+97
-11
@@ -34,6 +34,17 @@ extern "C" {
|
|||||||
* In which case, resize it down to free some memory */
|
* In which case, resize it down to free some memory */
|
||||||
#define ZSTD_WORKSPACETOOLARGE_MAXDURATION 128
|
#define ZSTD_WORKSPACETOOLARGE_MAXDURATION 128
|
||||||
|
|
||||||
|
/* Since the workspace is effectively its own little malloc implementation /
|
||||||
|
* arena, when we run under ASAN, we should similarly insert redzones between
|
||||||
|
* each internal element of the workspace, so ASAN will catch overruns that
|
||||||
|
* reach outside an object but that stay inside the workspace.
|
||||||
|
*
|
||||||
|
* This defines the size of that redzone.
|
||||||
|
*/
|
||||||
|
#ifndef ZSTD_CWKSP_ASAN_REDZONE_SIZE
|
||||||
|
#define ZSTD_CWKSP_ASAN_REDZONE_SIZE 128
|
||||||
|
#endif
|
||||||
|
|
||||||
/*-*************************************
|
/*-*************************************
|
||||||
* Structures
|
* Structures
|
||||||
***************************************/
|
***************************************/
|
||||||
@@ -166,6 +177,24 @@ MEM_STATIC size_t ZSTD_cwksp_align(size_t size, size_t const align) {
|
|||||||
return (size + mask) & ~mask;
|
return (size + mask) & ~mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this to determine how much space in the workspace we will consume to
|
||||||
|
* allocate this object. (Normally it should be exactly the size of the object,
|
||||||
|
* but under special conditions, like ASAN, where we pad each object, it might
|
||||||
|
* be larger.)
|
||||||
|
*
|
||||||
|
* Since tables aren't currently redzoned, you don't need to call through this
|
||||||
|
* to figure out how much space you need for the matchState tables. Everything
|
||||||
|
* else is though.
|
||||||
|
*/
|
||||||
|
MEM_STATIC size_t ZSTD_cwksp_alloc_size(size_t size) {
|
||||||
|
#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
|
||||||
|
return size + 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE;
|
||||||
|
#else
|
||||||
|
return size;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
MEM_STATIC void ZSTD_cwksp_internal_advance_phase(
|
MEM_STATIC void ZSTD_cwksp_internal_advance_phase(
|
||||||
ZSTD_cwksp* ws, ZSTD_cwksp_alloc_phase_e phase) {
|
ZSTD_cwksp* ws, ZSTD_cwksp_alloc_phase_e phase) {
|
||||||
assert(phase >= ws->phase);
|
assert(phase >= ws->phase);
|
||||||
@@ -192,6 +221,13 @@ MEM_STATIC void ZSTD_cwksp_internal_advance_phase(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether this object/buffer/etc was allocated in this workspace.
|
||||||
|
*/
|
||||||
|
MEM_STATIC int ZSTD_cwksp_owns_buffer(const ZSTD_cwksp* ws, const void* ptr) {
|
||||||
|
return (ptr != NULL) && (ws->workspace <= ptr) && (ptr <= ws->workspaceEnd);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal function. Do not use directly.
|
* Internal function. Do not use directly.
|
||||||
*/
|
*/
|
||||||
@@ -201,8 +237,14 @@ MEM_STATIC void* ZSTD_cwksp_reserve_internal(
|
|||||||
void* bottom = ws->tableEnd;
|
void* bottom = ws->tableEnd;
|
||||||
ZSTD_cwksp_internal_advance_phase(ws, phase);
|
ZSTD_cwksp_internal_advance_phase(ws, phase);
|
||||||
alloc = (BYTE *)ws->allocStart - bytes;
|
alloc = (BYTE *)ws->allocStart - bytes;
|
||||||
DEBUGLOG(5, "cwksp: reserving %zd bytes, %zd bytes remaining",
|
|
||||||
bytes, ZSTD_cwksp_available_space(ws) - bytes);
|
#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
|
||||||
|
/* over-reserve space */
|
||||||
|
alloc = (BYTE *)alloc - 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DEBUGLOG(5, "cwksp: reserving %p %zd bytes, %zd bytes remaining",
|
||||||
|
alloc, bytes, ZSTD_cwksp_available_space(ws) - bytes);
|
||||||
ZSTD_cwksp_assert_internal_consistency(ws);
|
ZSTD_cwksp_assert_internal_consistency(ws);
|
||||||
assert(alloc >= bottom);
|
assert(alloc >= bottom);
|
||||||
if (alloc < bottom) {
|
if (alloc < bottom) {
|
||||||
@@ -214,6 +256,14 @@ MEM_STATIC void* ZSTD_cwksp_reserve_internal(
|
|||||||
ws->tableValidEnd = alloc;
|
ws->tableValidEnd = alloc;
|
||||||
}
|
}
|
||||||
ws->allocStart = alloc;
|
ws->allocStart = alloc;
|
||||||
|
|
||||||
|
#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
|
||||||
|
/* Move alloc so there's ZSTD_CWKSP_ASAN_REDZONE_SIZE unused space on
|
||||||
|
* either size. */
|
||||||
|
alloc = (BYTE *)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE;
|
||||||
|
__asan_unpoison_memory_region(alloc, bytes);
|
||||||
|
#endif
|
||||||
|
|
||||||
return alloc;
|
return alloc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,8 +292,9 @@ MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes) {
|
|||||||
void* alloc = ws->tableEnd;
|
void* alloc = ws->tableEnd;
|
||||||
void* end = (BYTE *)alloc + bytes;
|
void* end = (BYTE *)alloc + bytes;
|
||||||
void* top = ws->allocStart;
|
void* top = ws->allocStart;
|
||||||
DEBUGLOG(5, "cwksp: reserving table %zd bytes, %zd bytes remaining",
|
|
||||||
bytes, ZSTD_cwksp_available_space(ws) - bytes);
|
DEBUGLOG(5, "cwksp: reserving %p table %zd bytes, %zd bytes remaining",
|
||||||
|
alloc, bytes, ZSTD_cwksp_available_space(ws) - bytes);
|
||||||
assert((bytes & (sizeof(U32)-1)) == 0);
|
assert((bytes & (sizeof(U32)-1)) == 0);
|
||||||
ZSTD_cwksp_internal_advance_phase(ws, phase);
|
ZSTD_cwksp_internal_advance_phase(ws, phase);
|
||||||
ZSTD_cwksp_assert_internal_consistency(ws);
|
ZSTD_cwksp_assert_internal_consistency(ws);
|
||||||
@@ -254,6 +305,11 @@ MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
ws->tableEnd = end;
|
ws->tableEnd = end;
|
||||||
|
|
||||||
|
#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
|
||||||
|
__asan_unpoison_memory_region(alloc, bytes);
|
||||||
|
#endif
|
||||||
|
|
||||||
return alloc;
|
return alloc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,12 +318,18 @@ MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes) {
|
|||||||
*/
|
*/
|
||||||
MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) {
|
MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) {
|
||||||
size_t roundedBytes = ZSTD_cwksp_align(bytes, sizeof(void*));
|
size_t roundedBytes = ZSTD_cwksp_align(bytes, sizeof(void*));
|
||||||
void* start = ws->objectEnd;
|
void* alloc = ws->objectEnd;
|
||||||
void* end = (BYTE*)start + roundedBytes;
|
void* end = (BYTE*)alloc + roundedBytes;
|
||||||
|
|
||||||
|
#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
|
||||||
|
/* over-reserve space */
|
||||||
|
end = (BYTE *)end + 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE;
|
||||||
|
#endif
|
||||||
|
|
||||||
DEBUGLOG(5,
|
DEBUGLOG(5,
|
||||||
"cwksp: reserving object %zd bytes (rounded to %zd), %zd bytes remaining",
|
"cwksp: reserving %p object %zd bytes (rounded to %zd), %zd bytes remaining",
|
||||||
bytes, roundedBytes, ZSTD_cwksp_available_space(ws) - roundedBytes);
|
alloc, bytes, roundedBytes, ZSTD_cwksp_available_space(ws) - roundedBytes);
|
||||||
assert(((size_t)start & (sizeof(void*)-1)) == 0);
|
assert(((size_t)alloc & (sizeof(void*)-1)) == 0);
|
||||||
assert((bytes & (sizeof(void*)-1)) == 0);
|
assert((bytes & (sizeof(void*)-1)) == 0);
|
||||||
ZSTD_cwksp_assert_internal_consistency(ws);
|
ZSTD_cwksp_assert_internal_consistency(ws);
|
||||||
/* we must be in the first phase, no advance is possible */
|
/* we must be in the first phase, no advance is possible */
|
||||||
@@ -279,7 +341,15 @@ MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) {
|
|||||||
ws->objectEnd = end;
|
ws->objectEnd = end;
|
||||||
ws->tableEnd = end;
|
ws->tableEnd = end;
|
||||||
ws->tableValidEnd = end;
|
ws->tableValidEnd = end;
|
||||||
return start;
|
|
||||||
|
#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
|
||||||
|
/* Move alloc so there's ZSTD_CWKSP_ASAN_REDZONE_SIZE unused space on
|
||||||
|
* either size. */
|
||||||
|
alloc = (BYTE *)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE;
|
||||||
|
__asan_unpoison_memory_region(alloc, bytes);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return alloc;
|
||||||
}
|
}
|
||||||
|
|
||||||
MEM_STATIC void ZSTD_cwksp_mark_tables_dirty(ZSTD_cwksp* ws) {
|
MEM_STATIC void ZSTD_cwksp_mark_tables_dirty(ZSTD_cwksp* ws) {
|
||||||
@@ -331,6 +401,14 @@ MEM_STATIC void ZSTD_cwksp_clean_tables(ZSTD_cwksp* ws) {
|
|||||||
*/
|
*/
|
||||||
MEM_STATIC void ZSTD_cwksp_clear_tables(ZSTD_cwksp* ws) {
|
MEM_STATIC void ZSTD_cwksp_clear_tables(ZSTD_cwksp* ws) {
|
||||||
DEBUGLOG(4, "cwksp: clearing tables!");
|
DEBUGLOG(4, "cwksp: clearing tables!");
|
||||||
|
|
||||||
|
#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
|
||||||
|
{
|
||||||
|
size_t size = (BYTE*)ws->tableValidEnd - (BYTE*)ws->objectEnd;
|
||||||
|
__asan_poison_memory_region(ws->objectEnd, size);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
ws->tableEnd = ws->objectEnd;
|
ws->tableEnd = ws->objectEnd;
|
||||||
ZSTD_cwksp_assert_internal_consistency(ws);
|
ZSTD_cwksp_assert_internal_consistency(ws);
|
||||||
}
|
}
|
||||||
@@ -353,6 +431,13 @@ MEM_STATIC void ZSTD_cwksp_clear(ZSTD_cwksp* ws) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined (ADDRESS_SANITIZER) && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
|
||||||
|
{
|
||||||
|
size_t size = (BYTE*)ws->workspaceEnd - (BYTE*)ws->objectEnd;
|
||||||
|
__asan_poison_memory_region(ws->objectEnd, size);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
ws->tableEnd = ws->objectEnd;
|
ws->tableEnd = ws->objectEnd;
|
||||||
ws->allocStart = ws->workspaceEnd;
|
ws->allocStart = ws->workspaceEnd;
|
||||||
ws->allocFailed = 0;
|
ws->allocFailed = 0;
|
||||||
@@ -389,9 +474,10 @@ MEM_STATIC size_t ZSTD_cwksp_create(ZSTD_cwksp* ws, size_t size, ZSTD_customMem
|
|||||||
}
|
}
|
||||||
|
|
||||||
MEM_STATIC void ZSTD_cwksp_free(ZSTD_cwksp* ws, ZSTD_customMem customMem) {
|
MEM_STATIC void ZSTD_cwksp_free(ZSTD_cwksp* ws, ZSTD_customMem customMem) {
|
||||||
|
void *ptr = ws->workspace;
|
||||||
DEBUGLOG(4, "cwksp: freeing workspace");
|
DEBUGLOG(4, "cwksp: freeing workspace");
|
||||||
ZSTD_free(ws->workspace, customMem);
|
|
||||||
memset(ws, 0, sizeof(ZSTD_cwksp));
|
memset(ws, 0, sizeof(ZSTD_cwksp));
|
||||||
|
ZSTD_free(ptr, customMem);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -49,9 +49,9 @@ size_t ZSTD_ldm_getTableSize(ldmParams_t params)
|
|||||||
{
|
{
|
||||||
size_t const ldmHSize = ((size_t)1) << params.hashLog;
|
size_t const ldmHSize = ((size_t)1) << params.hashLog;
|
||||||
size_t const ldmBucketSizeLog = MIN(params.bucketSizeLog, params.hashLog);
|
size_t const ldmBucketSizeLog = MIN(params.bucketSizeLog, params.hashLog);
|
||||||
size_t const ldmBucketSize =
|
size_t const ldmBucketSize = ((size_t)1) << (params.hashLog - ldmBucketSizeLog);
|
||||||
((size_t)1) << (params.hashLog - ldmBucketSizeLog);
|
size_t const totalSize = ZSTD_cwksp_alloc_size(ldmBucketSize)
|
||||||
size_t const totalSize = ldmBucketSize + ldmHSize * sizeof(ldmEntry_t);
|
+ ZSTD_cwksp_alloc_size(ldmHSize * sizeof(ldmEntry_t));
|
||||||
return params.enableLdm ? totalSize : 0;
|
return params.enableLdm ? totalSize : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user