[lib] Validate buffers when ZSTD_c_stable{In,Out}Buffer is set

Adds the validation of the input/output buffers only. They are still
unused.
This commit is contained in:
Nick Terrell
2020-10-30 10:55:34 -07:00
parent e3e0775cc8
commit c74be3f6de
4 changed files with 48 additions and 1 deletions
+1
View File
@@ -48,6 +48,7 @@ const char* ERR_getErrorString(ERR_enum code)
case PREFIX(frameIndex_tooLarge): return "Frame index is too large"; case PREFIX(frameIndex_tooLarge): return "Frame index is too large";
case PREFIX(seekableIO): return "An I/O error occurred when reading/seeking"; case PREFIX(seekableIO): return "An I/O error occurred when reading/seeking";
case PREFIX(dstBuffer_wrong): return "Destination buffer is wrong"; case PREFIX(dstBuffer_wrong): return "Destination buffer is wrong";
case PREFIX(srcBuffer_wrong): return "Source buffer is wrong";
case PREFIX(maxCode): case PREFIX(maxCode):
default: return notErrorCode; default: return notErrorCode;
} }
+1
View File
@@ -77,6 +77,7 @@ typedef enum {
ZSTD_error_frameIndex_tooLarge = 100, ZSTD_error_frameIndex_tooLarge = 100,
ZSTD_error_seekableIO = 102, ZSTD_error_seekableIO = 102,
ZSTD_error_dstBuffer_wrong = 104, ZSTD_error_dstBuffer_wrong = 104,
ZSTD_error_srcBuffer_wrong = 105,
ZSTD_error_maxCode = 120 /* never EVER use this value directly, it can change in future versions! Use ZSTD_isError() instead */ ZSTD_error_maxCode = 120 /* never EVER use this value directly, it can change in future versions! Use ZSTD_isError() instead */
} ZSTD_ErrorCode; } ZSTD_ErrorCode;
+42 -1
View File
@@ -4193,6 +4193,41 @@ size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuf
return ZSTD_nextInputSizeHint_MTorST(zcs); return ZSTD_nextInputSizeHint_MTorST(zcs);
} }
/* After a compression call set the expected input/output buffer.
* This is validated at the start of the next compression call.
*/
static void ZSTD_setBufferExpectations(ZSTD_CCtx* cctx, ZSTD_outBuffer const* output, ZSTD_inBuffer const* input)
{
if (cctx->appliedParams.inBufferMode == ZSTD_bm_stable) {
cctx->expectedInBuffer = *input;
}
if (cctx->appliedParams.outBufferMode == ZSTD_bm_stable) {
cctx->expectedOutBufferSize = output->size - output->pos;
}
}
/* Validate that the input/output buffers match the expectations set by
* ZSTD_setBufferExpectations.
*/
static size_t ZSTD_checkBufferStability(ZSTD_CCtx const* cctx,
ZSTD_outBuffer const* output,
ZSTD_inBuffer const* input,
ZSTD_EndDirective endOp)
{
if (cctx->appliedParams.inBufferMode == ZSTD_bm_stable) {
ZSTD_inBuffer const expect = cctx->expectedInBuffer;
if (expect.src != input->src || expect.pos != input->pos || expect.size != input->size)
RETURN_ERROR(srcBuffer_wrong, "ZSTD_c_stableInBuffer enabled but input differs!");
if (endOp != ZSTD_e_end)
RETURN_ERROR(srcBuffer_wrong, "ZSTD_c_stableInBuffer can only be used with ZSTD_e_end!");
}
if (cctx->appliedParams.outBufferMode == ZSTD_bm_stable) {
size_t const outBufferSize = output->size - output->pos;
if (cctx->expectedOutBufferSize != outBufferSize)
RETURN_ERROR(dstBuffer_wrong, "ZSTD_c_stableOutBuffer enabled but output size differs!");
}
return 0;
}
size_t ZSTD_compressStream2( ZSTD_CCtx* cctx, size_t ZSTD_compressStream2( ZSTD_CCtx* cctx,
ZSTD_outBuffer* output, ZSTD_outBuffer* output,
@@ -4270,9 +4305,13 @@ size_t ZSTD_compressStream2( ZSTD_CCtx* cctx,
cctx->outBuffContentSize = cctx->outBuffFlushedSize = 0; cctx->outBuffContentSize = cctx->outBuffFlushedSize = 0;
cctx->streamStage = zcss_load; cctx->streamStage = zcss_load;
cctx->frameEnded = 0; cctx->frameEnded = 0;
} } }
/* Set initial buffer expectations now that we've initialized */
ZSTD_setBufferExpectations(cctx, output, input);
}
/* end of transparent initialization stage */ /* end of transparent initialization stage */
FORWARD_IF_ERROR(ZSTD_checkBufferStability(cctx, output, input, endOp), "invalid buffers");
/* compression stage */ /* compression stage */
#ifdef ZSTD_MULTITHREAD #ifdef ZSTD_MULTITHREAD
if (cctx->appliedParams.nbWorkers > 0) { if (cctx->appliedParams.nbWorkers > 0) {
@@ -4296,11 +4335,13 @@ size_t ZSTD_compressStream2( ZSTD_CCtx* cctx,
* flush, or we are out of output space. * flush, or we are out of output space.
*/ */
assert(!forceMaxProgress || flushMin == 0 || output->pos == output->size); assert(!forceMaxProgress || flushMin == 0 || output->pos == output->size);
ZSTD_setBufferExpectations(cctx, output, input);
return flushMin; return flushMin;
} }
#endif #endif
FORWARD_IF_ERROR( ZSTD_compressStream_generic(cctx, output, input, endOp) , ""); FORWARD_IF_ERROR( ZSTD_compressStream_generic(cctx, output, input, endOp) , "");
DEBUGLOG(5, "completed ZSTD_compressStream2"); DEBUGLOG(5, "completed ZSTD_compressStream2");
ZSTD_setBufferExpectations(cctx, output, input);
return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */ return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */
} }
+4
View File
@@ -291,6 +291,10 @@ struct ZSTD_CCtx_s {
ZSTD_cStreamStage streamStage; ZSTD_cStreamStage streamStage;
U32 frameEnded; U32 frameEnded;
/* Stable in/out buffer verification */
ZSTD_inBuffer expectedInBuffer;
size_t expectedOutBufferSize;
/* Dictionary */ /* Dictionary */
ZSTD_localDict localDict; ZSTD_localDict localDict;
const ZSTD_CDict* cdict; const ZSTD_CDict* cdict;