extzstd 0.3.2 → 0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +4 -3
- data/contrib/zstd/CHANGELOG +225 -1
- data/contrib/zstd/CONTRIBUTING.md +158 -75
- data/contrib/zstd/LICENSE +4 -4
- data/contrib/zstd/Makefile +106 -69
- data/contrib/zstd/Package.swift +36 -0
- data/contrib/zstd/README.md +64 -36
- data/contrib/zstd/SECURITY.md +15 -0
- data/contrib/zstd/TESTING.md +2 -3
- data/contrib/zstd/lib/BUCK +5 -7
- data/contrib/zstd/lib/Makefile +117 -199
- data/contrib/zstd/lib/README.md +37 -7
- data/contrib/zstd/lib/common/allocations.h +55 -0
- data/contrib/zstd/lib/common/bits.h +200 -0
- data/contrib/zstd/lib/common/bitstream.h +80 -86
- data/contrib/zstd/lib/common/compiler.h +225 -63
- data/contrib/zstd/lib/common/cpu.h +37 -1
- data/contrib/zstd/lib/common/debug.c +7 -1
- data/contrib/zstd/lib/common/debug.h +21 -12
- data/contrib/zstd/lib/common/entropy_common.c +15 -37
- data/contrib/zstd/lib/common/error_private.c +9 -2
- data/contrib/zstd/lib/common/error_private.h +93 -5
- data/contrib/zstd/lib/common/fse.h +12 -87
- data/contrib/zstd/lib/common/fse_decompress.c +37 -117
- data/contrib/zstd/lib/common/huf.h +97 -172
- data/contrib/zstd/lib/common/mem.h +58 -58
- data/contrib/zstd/lib/common/pool.c +38 -17
- data/contrib/zstd/lib/common/pool.h +10 -4
- data/contrib/zstd/lib/common/portability_macros.h +158 -0
- data/contrib/zstd/lib/common/threading.c +74 -14
- data/contrib/zstd/lib/common/threading.h +5 -10
- data/contrib/zstd/lib/common/xxhash.c +6 -814
- data/contrib/zstd/lib/common/xxhash.h +6930 -195
- data/contrib/zstd/lib/common/zstd_common.c +1 -36
- data/contrib/zstd/lib/common/zstd_deps.h +1 -1
- data/contrib/zstd/lib/common/zstd_internal.h +68 -154
- data/contrib/zstd/lib/common/zstd_trace.h +163 -0
- data/contrib/zstd/lib/compress/clevels.h +134 -0
- data/contrib/zstd/lib/compress/fse_compress.c +75 -155
- data/contrib/zstd/lib/compress/hist.c +1 -1
- data/contrib/zstd/lib/compress/hist.h +1 -1
- data/contrib/zstd/lib/compress/huf_compress.c +810 -259
- data/contrib/zstd/lib/compress/zstd_compress.c +2864 -919
- data/contrib/zstd/lib/compress/zstd_compress_internal.h +523 -192
- data/contrib/zstd/lib/compress/zstd_compress_literals.c +117 -40
- data/contrib/zstd/lib/compress/zstd_compress_literals.h +16 -6
- data/contrib/zstd/lib/compress/zstd_compress_sequences.c +28 -19
- data/contrib/zstd/lib/compress/zstd_compress_sequences.h +1 -1
- data/contrib/zstd/lib/compress/zstd_compress_superblock.c +251 -412
- data/contrib/zstd/lib/compress/zstd_compress_superblock.h +1 -1
- data/contrib/zstd/lib/compress/zstd_cwksp.h +284 -97
- data/contrib/zstd/lib/compress/zstd_double_fast.c +382 -133
- data/contrib/zstd/lib/compress/zstd_double_fast.h +14 -2
- data/contrib/zstd/lib/compress/zstd_fast.c +732 -260
- data/contrib/zstd/lib/compress/zstd_fast.h +3 -2
- data/contrib/zstd/lib/compress/zstd_lazy.c +1177 -390
- data/contrib/zstd/lib/compress/zstd_lazy.h +129 -14
- data/contrib/zstd/lib/compress/zstd_ldm.c +280 -210
- data/contrib/zstd/lib/compress/zstd_ldm.h +3 -2
- data/contrib/zstd/lib/compress/zstd_ldm_geartab.h +106 -0
- data/contrib/zstd/lib/compress/zstd_opt.c +516 -285
- data/contrib/zstd/lib/compress/zstd_opt.h +32 -8
- data/contrib/zstd/lib/compress/zstdmt_compress.c +202 -131
- data/contrib/zstd/lib/compress/zstdmt_compress.h +9 -6
- data/contrib/zstd/lib/decompress/huf_decompress.c +1149 -555
- data/contrib/zstd/lib/decompress/huf_decompress_amd64.S +595 -0
- data/contrib/zstd/lib/decompress/zstd_ddict.c +4 -4
- data/contrib/zstd/lib/decompress/zstd_ddict.h +1 -1
- data/contrib/zstd/lib/decompress/zstd_decompress.c +583 -106
- data/contrib/zstd/lib/decompress/zstd_decompress_block.c +1054 -379
- data/contrib/zstd/lib/decompress/zstd_decompress_block.h +14 -3
- data/contrib/zstd/lib/decompress/zstd_decompress_internal.h +56 -6
- data/contrib/zstd/lib/deprecated/zbuff.h +1 -1
- data/contrib/zstd/lib/deprecated/zbuff_common.c +1 -1
- data/contrib/zstd/lib/deprecated/zbuff_compress.c +24 -4
- data/contrib/zstd/lib/deprecated/zbuff_decompress.c +3 -1
- data/contrib/zstd/lib/dictBuilder/cover.c +60 -44
- data/contrib/zstd/lib/dictBuilder/cover.h +6 -11
- data/contrib/zstd/lib/dictBuilder/divsufsort.c +1 -1
- data/contrib/zstd/lib/dictBuilder/fastcover.c +26 -18
- data/contrib/zstd/lib/dictBuilder/zdict.c +100 -101
- data/contrib/zstd/lib/legacy/zstd_legacy.h +38 -1
- data/contrib/zstd/lib/legacy/zstd_v01.c +18 -53
- data/contrib/zstd/lib/legacy/zstd_v01.h +1 -1
- data/contrib/zstd/lib/legacy/zstd_v02.c +28 -85
- data/contrib/zstd/lib/legacy/zstd_v02.h +1 -1
- data/contrib/zstd/lib/legacy/zstd_v03.c +29 -88
- data/contrib/zstd/lib/legacy/zstd_v03.h +1 -1
- data/contrib/zstd/lib/legacy/zstd_v04.c +27 -80
- data/contrib/zstd/lib/legacy/zstd_v04.h +1 -1
- data/contrib/zstd/lib/legacy/zstd_v05.c +36 -85
- data/contrib/zstd/lib/legacy/zstd_v05.h +1 -1
- data/contrib/zstd/lib/legacy/zstd_v06.c +44 -96
- data/contrib/zstd/lib/legacy/zstd_v06.h +1 -1
- data/contrib/zstd/lib/legacy/zstd_v07.c +37 -92
- data/contrib/zstd/lib/legacy/zstd_v07.h +1 -1
- data/contrib/zstd/lib/libzstd.mk +237 -0
- data/contrib/zstd/lib/libzstd.pc.in +4 -3
- data/contrib/zstd/lib/module.modulemap +35 -0
- data/contrib/zstd/lib/{dictBuilder/zdict.h → zdict.h} +202 -33
- data/contrib/zstd/lib/zstd.h +1030 -332
- data/contrib/zstd/lib/{common/zstd_errors.h → zstd_errors.h} +27 -8
- data/ext/extconf.rb +26 -7
- data/ext/extzstd.c +51 -24
- data/ext/extzstd.h +33 -6
- data/ext/extzstd_stream.c +74 -31
- data/ext/libzstd_conf.h +0 -1
- data/ext/zstd_decompress_asm.S +1 -0
- metadata +17 -7
- data/contrib/zstd/appveyor.yml +0 -292
- data/ext/depend +0 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* Copyright (c)
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
3
|
* All rights reserved.
|
|
4
4
|
*
|
|
5
5
|
* This source code is licensed under both the BSD-style license (found in the
|
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
/*-*************************************
|
|
15
15
|
* Dependencies
|
|
16
16
|
***************************************/
|
|
17
|
+
#include "../common/allocations.h" /* ZSTD_customMalloc, ZSTD_customFree */
|
|
17
18
|
#include "../common/zstd_internal.h"
|
|
19
|
+
#include "../common/portability_macros.h"
|
|
18
20
|
|
|
19
21
|
#if defined (__cplusplus)
|
|
20
22
|
extern "C" {
|
|
@@ -35,13 +37,18 @@ extern "C" {
|
|
|
35
37
|
#define ZSTD_CWKSP_ASAN_REDZONE_SIZE 128
|
|
36
38
|
#endif
|
|
37
39
|
|
|
40
|
+
|
|
41
|
+
/* Set our tables and aligneds to align by 64 bytes */
|
|
42
|
+
#define ZSTD_CWKSP_ALIGNMENT_BYTES 64
|
|
43
|
+
|
|
38
44
|
/*-*************************************
|
|
39
45
|
* Structures
|
|
40
46
|
***************************************/
|
|
41
47
|
typedef enum {
|
|
42
48
|
ZSTD_cwksp_alloc_objects,
|
|
43
|
-
|
|
44
|
-
ZSTD_cwksp_alloc_aligned
|
|
49
|
+
ZSTD_cwksp_alloc_aligned_init_once,
|
|
50
|
+
ZSTD_cwksp_alloc_aligned,
|
|
51
|
+
ZSTD_cwksp_alloc_buffers
|
|
45
52
|
} ZSTD_cwksp_alloc_phase_e;
|
|
46
53
|
|
|
47
54
|
/**
|
|
@@ -94,8 +101,8 @@ typedef enum {
|
|
|
94
101
|
*
|
|
95
102
|
* Workspace Layout:
|
|
96
103
|
*
|
|
97
|
-
* [ ... workspace ...
|
|
98
|
-
* [objects][tables
|
|
104
|
+
* [ ... workspace ... ]
|
|
105
|
+
* [objects][tables ->] free space [<- buffers][<- aligned][<- init once]
|
|
99
106
|
*
|
|
100
107
|
* The various objects that live in the workspace are divided into the
|
|
101
108
|
* following categories, and are allocated separately:
|
|
@@ -117,10 +124,20 @@ typedef enum {
|
|
|
117
124
|
* - Tables: these are any of several different datastructures (hash tables,
|
|
118
125
|
* chain tables, binary trees) that all respect a common format: they are
|
|
119
126
|
* uint32_t arrays, all of whose values are between 0 and (nextSrc - base).
|
|
120
|
-
* Their sizes depend on the cparams.
|
|
127
|
+
* Their sizes depend on the cparams. These tables are 64-byte aligned.
|
|
121
128
|
*
|
|
122
|
-
* -
|
|
123
|
-
*
|
|
129
|
+
* - Init once: these buffers require to be initialized at least once before
|
|
130
|
+
* use. They should be used when we want to skip memory initialization
|
|
131
|
+
* while not triggering memory checkers (like Valgrind) when reading from
|
|
132
|
+
* from this memory without writing to it first.
|
|
133
|
+
* These buffers should be used carefully as they might contain data
|
|
134
|
+
* from previous compressions.
|
|
135
|
+
* Buffers are aligned to 64 bytes.
|
|
136
|
+
*
|
|
137
|
+
* - Aligned: these buffers don't require any initialization before they're
|
|
138
|
+
* used. The user of the buffer should make sure they write into a buffer
|
|
139
|
+
* location before reading from it.
|
|
140
|
+
* Buffers are aligned to 64 bytes.
|
|
124
141
|
*
|
|
125
142
|
* - Buffers: these buffers are used for various purposes that don't require
|
|
126
143
|
* any alignment or initialization before they're used. This means they can
|
|
@@ -132,9 +149,9 @@ typedef enum {
|
|
|
132
149
|
* correctly packed into the workspace buffer. That order is:
|
|
133
150
|
*
|
|
134
151
|
* 1. Objects
|
|
135
|
-
* 2.
|
|
136
|
-
* 3. Aligned
|
|
137
|
-
* 4. Tables
|
|
152
|
+
* 2. Init once / Tables
|
|
153
|
+
* 3. Aligned / Tables
|
|
154
|
+
* 4. Buffers / Tables
|
|
138
155
|
*
|
|
139
156
|
* Attempts to reserve objects of different types out of order will fail.
|
|
140
157
|
*/
|
|
@@ -146,6 +163,7 @@ typedef struct {
|
|
|
146
163
|
void* tableEnd;
|
|
147
164
|
void* tableValidEnd;
|
|
148
165
|
void* allocStart;
|
|
166
|
+
void* initOnceStart;
|
|
149
167
|
|
|
150
168
|
BYTE allocFailed;
|
|
151
169
|
int workspaceOversizedDuration;
|
|
@@ -158,6 +176,7 @@ typedef struct {
|
|
|
158
176
|
***************************************/
|
|
159
177
|
|
|
160
178
|
MEM_STATIC size_t ZSTD_cwksp_available_space(ZSTD_cwksp* ws);
|
|
179
|
+
MEM_STATIC void* ZSTD_cwksp_initialAllocStart(ZSTD_cwksp* ws);
|
|
161
180
|
|
|
162
181
|
MEM_STATIC void ZSTD_cwksp_assert_internal_consistency(ZSTD_cwksp* ws) {
|
|
163
182
|
(void)ws;
|
|
@@ -167,6 +186,21 @@ MEM_STATIC void ZSTD_cwksp_assert_internal_consistency(ZSTD_cwksp* ws) {
|
|
|
167
186
|
assert(ws->tableEnd <= ws->allocStart);
|
|
168
187
|
assert(ws->tableValidEnd <= ws->allocStart);
|
|
169
188
|
assert(ws->allocStart <= ws->workspaceEnd);
|
|
189
|
+
assert(ws->initOnceStart <= ZSTD_cwksp_initialAllocStart(ws));
|
|
190
|
+
assert(ws->workspace <= ws->initOnceStart);
|
|
191
|
+
#if ZSTD_MEMORY_SANITIZER
|
|
192
|
+
{
|
|
193
|
+
intptr_t const offset = __msan_test_shadow(ws->initOnceStart,
|
|
194
|
+
(U8*)ZSTD_cwksp_initialAllocStart(ws) - (U8*)ws->initOnceStart);
|
|
195
|
+
(void)offset;
|
|
196
|
+
#if defined(ZSTD_MSAN_PRINT)
|
|
197
|
+
if(offset!=-1) {
|
|
198
|
+
__msan_print_shadow((U8*)ws->initOnceStart + offset - 8, 32);
|
|
199
|
+
}
|
|
200
|
+
#endif
|
|
201
|
+
assert(offset==-1);
|
|
202
|
+
};
|
|
203
|
+
#endif
|
|
170
204
|
}
|
|
171
205
|
|
|
172
206
|
/**
|
|
@@ -187,6 +221,8 @@ MEM_STATIC size_t ZSTD_cwksp_align(size_t size, size_t const align) {
|
|
|
187
221
|
* Since tables aren't currently redzoned, you don't need to call through this
|
|
188
222
|
* to figure out how much space you need for the matchState tables. Everything
|
|
189
223
|
* else is though.
|
|
224
|
+
*
|
|
225
|
+
* Do not use for sizing aligned buffers. Instead, use ZSTD_cwksp_aligned_alloc_size().
|
|
190
226
|
*/
|
|
191
227
|
MEM_STATIC size_t ZSTD_cwksp_alloc_size(size_t size) {
|
|
192
228
|
if (size == 0)
|
|
@@ -198,77 +234,149 @@ MEM_STATIC size_t ZSTD_cwksp_alloc_size(size_t size) {
|
|
|
198
234
|
#endif
|
|
199
235
|
}
|
|
200
236
|
|
|
201
|
-
|
|
202
|
-
|
|
237
|
+
/**
|
|
238
|
+
* Returns an adjusted alloc size that is the nearest larger multiple of 64 bytes.
|
|
239
|
+
* Used to determine the number of bytes required for a given "aligned".
|
|
240
|
+
*/
|
|
241
|
+
MEM_STATIC size_t ZSTD_cwksp_aligned_alloc_size(size_t size) {
|
|
242
|
+
return ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(size, ZSTD_CWKSP_ALIGNMENT_BYTES));
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Returns the amount of additional space the cwksp must allocate
|
|
247
|
+
* for internal purposes (currently only alignment).
|
|
248
|
+
*/
|
|
249
|
+
MEM_STATIC size_t ZSTD_cwksp_slack_space_required(void) {
|
|
250
|
+
/* For alignment, the wksp will always allocate an additional 2*ZSTD_CWKSP_ALIGNMENT_BYTES
|
|
251
|
+
* bytes to align the beginning of tables section and end of buffers;
|
|
252
|
+
*/
|
|
253
|
+
size_t const slackSpace = ZSTD_CWKSP_ALIGNMENT_BYTES * 2;
|
|
254
|
+
return slackSpace;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Return the number of additional bytes required to align a pointer to the given number of bytes.
|
|
260
|
+
* alignBytes must be a power of two.
|
|
261
|
+
*/
|
|
262
|
+
MEM_STATIC size_t ZSTD_cwksp_bytes_to_align_ptr(void* ptr, const size_t alignBytes) {
|
|
263
|
+
size_t const alignBytesMask = alignBytes - 1;
|
|
264
|
+
size_t const bytes = (alignBytes - ((size_t)ptr & (alignBytesMask))) & alignBytesMask;
|
|
265
|
+
assert((alignBytes & alignBytesMask) == 0);
|
|
266
|
+
assert(bytes < alignBytes);
|
|
267
|
+
return bytes;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Returns the initial value for allocStart which is used to determine the position from
|
|
272
|
+
* which we can allocate from the end of the workspace.
|
|
273
|
+
*/
|
|
274
|
+
MEM_STATIC void* ZSTD_cwksp_initialAllocStart(ZSTD_cwksp* ws) {
|
|
275
|
+
return (void*)((size_t)ws->workspaceEnd & ~(ZSTD_CWKSP_ALIGNMENT_BYTES-1));
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Internal function. Do not use directly.
|
|
280
|
+
* Reserves the given number of bytes within the aligned/buffer segment of the wksp,
|
|
281
|
+
* which counts from the end of the wksp (as opposed to the object/table segment).
|
|
282
|
+
*
|
|
283
|
+
* Returns a pointer to the beginning of that space.
|
|
284
|
+
*/
|
|
285
|
+
MEM_STATIC void*
|
|
286
|
+
ZSTD_cwksp_reserve_internal_buffer_space(ZSTD_cwksp* ws, size_t const bytes)
|
|
287
|
+
{
|
|
288
|
+
void* const alloc = (BYTE*)ws->allocStart - bytes;
|
|
289
|
+
void* const bottom = ws->tableEnd;
|
|
290
|
+
DEBUGLOG(5, "cwksp: reserving %p %zd bytes, %zd bytes remaining",
|
|
291
|
+
alloc, bytes, ZSTD_cwksp_available_space(ws) - bytes);
|
|
292
|
+
ZSTD_cwksp_assert_internal_consistency(ws);
|
|
293
|
+
assert(alloc >= bottom);
|
|
294
|
+
if (alloc < bottom) {
|
|
295
|
+
DEBUGLOG(4, "cwksp: alloc failed!");
|
|
296
|
+
ws->allocFailed = 1;
|
|
297
|
+
return NULL;
|
|
298
|
+
}
|
|
299
|
+
/* the area is reserved from the end of wksp.
|
|
300
|
+
* If it overlaps with tableValidEnd, it voids guarantees on values' range */
|
|
301
|
+
if (alloc < ws->tableValidEnd) {
|
|
302
|
+
ws->tableValidEnd = alloc;
|
|
303
|
+
}
|
|
304
|
+
ws->allocStart = alloc;
|
|
305
|
+
return alloc;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Moves the cwksp to the next phase, and does any necessary allocations.
|
|
310
|
+
* cwksp initialization must necessarily go through each phase in order.
|
|
311
|
+
* Returns a 0 on success, or zstd error
|
|
312
|
+
*/
|
|
313
|
+
MEM_STATIC size_t
|
|
314
|
+
ZSTD_cwksp_internal_advance_phase(ZSTD_cwksp* ws, ZSTD_cwksp_alloc_phase_e phase)
|
|
315
|
+
{
|
|
203
316
|
assert(phase >= ws->phase);
|
|
204
317
|
if (phase > ws->phase) {
|
|
205
|
-
|
|
206
|
-
|
|
318
|
+
/* Going from allocating objects to allocating initOnce / tables */
|
|
319
|
+
if (ws->phase < ZSTD_cwksp_alloc_aligned_init_once &&
|
|
320
|
+
phase >= ZSTD_cwksp_alloc_aligned_init_once) {
|
|
207
321
|
ws->tableValidEnd = ws->objectEnd;
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
322
|
+
ws->initOnceStart = ZSTD_cwksp_initialAllocStart(ws);
|
|
323
|
+
|
|
324
|
+
{ /* Align the start of the tables to 64 bytes. Use [0, 63] bytes */
|
|
325
|
+
void *const alloc = ws->objectEnd;
|
|
326
|
+
size_t const bytesToAlign = ZSTD_cwksp_bytes_to_align_ptr(alloc, ZSTD_CWKSP_ALIGNMENT_BYTES);
|
|
327
|
+
void *const objectEnd = (BYTE *) alloc + bytesToAlign;
|
|
328
|
+
DEBUGLOG(5, "reserving table alignment addtl space: %zu", bytesToAlign);
|
|
329
|
+
RETURN_ERROR_IF(objectEnd > ws->workspaceEnd, memory_allocation,
|
|
330
|
+
"table phase - alignment initial allocation failed!");
|
|
331
|
+
ws->objectEnd = objectEnd;
|
|
332
|
+
ws->tableEnd = objectEnd; /* table area starts being empty */
|
|
333
|
+
if (ws->tableValidEnd < ws->tableEnd) {
|
|
334
|
+
ws->tableValidEnd = ws->tableEnd;
|
|
335
|
+
}
|
|
221
336
|
}
|
|
222
337
|
}
|
|
223
338
|
ws->phase = phase;
|
|
339
|
+
ZSTD_cwksp_assert_internal_consistency(ws);
|
|
224
340
|
}
|
|
341
|
+
return 0;
|
|
225
342
|
}
|
|
226
343
|
|
|
227
344
|
/**
|
|
228
345
|
* Returns whether this object/buffer/etc was allocated in this workspace.
|
|
229
346
|
*/
|
|
230
|
-
MEM_STATIC int ZSTD_cwksp_owns_buffer(const ZSTD_cwksp* ws, const void* ptr)
|
|
231
|
-
|
|
347
|
+
MEM_STATIC int ZSTD_cwksp_owns_buffer(const ZSTD_cwksp* ws, const void* ptr)
|
|
348
|
+
{
|
|
349
|
+
return (ptr != NULL) && (ws->workspace <= ptr) && (ptr < ws->workspaceEnd);
|
|
232
350
|
}
|
|
233
351
|
|
|
234
352
|
/**
|
|
235
353
|
* Internal function. Do not use directly.
|
|
236
354
|
*/
|
|
237
|
-
MEM_STATIC void*
|
|
238
|
-
|
|
355
|
+
MEM_STATIC void*
|
|
356
|
+
ZSTD_cwksp_reserve_internal(ZSTD_cwksp* ws, size_t bytes, ZSTD_cwksp_alloc_phase_e phase)
|
|
357
|
+
{
|
|
239
358
|
void* alloc;
|
|
240
|
-
|
|
241
|
-
ZSTD_cwksp_internal_advance_phase(ws, phase);
|
|
242
|
-
alloc = (BYTE *)ws->allocStart - bytes;
|
|
243
|
-
|
|
244
|
-
if (bytes == 0)
|
|
359
|
+
if (ZSTD_isError(ZSTD_cwksp_internal_advance_phase(ws, phase)) || bytes == 0) {
|
|
245
360
|
return NULL;
|
|
361
|
+
}
|
|
246
362
|
|
|
247
363
|
#if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
|
|
248
364
|
/* over-reserve space */
|
|
249
|
-
|
|
365
|
+
bytes += 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE;
|
|
250
366
|
#endif
|
|
251
367
|
|
|
252
|
-
|
|
253
|
-
alloc, bytes, ZSTD_cwksp_available_space(ws) - bytes);
|
|
254
|
-
ZSTD_cwksp_assert_internal_consistency(ws);
|
|
255
|
-
assert(alloc >= bottom);
|
|
256
|
-
if (alloc < bottom) {
|
|
257
|
-
DEBUGLOG(4, "cwksp: alloc failed!");
|
|
258
|
-
ws->allocFailed = 1;
|
|
259
|
-
return NULL;
|
|
260
|
-
}
|
|
261
|
-
if (alloc < ws->tableValidEnd) {
|
|
262
|
-
ws->tableValidEnd = alloc;
|
|
263
|
-
}
|
|
264
|
-
ws->allocStart = alloc;
|
|
368
|
+
alloc = ZSTD_cwksp_reserve_internal_buffer_space(ws, bytes);
|
|
265
369
|
|
|
266
370
|
#if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
|
|
267
371
|
/* Move alloc so there's ZSTD_CWKSP_ASAN_REDZONE_SIZE unused space on
|
|
268
372
|
* either size. */
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
373
|
+
if (alloc) {
|
|
374
|
+
alloc = (BYTE *)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE;
|
|
375
|
+
if (ws->isStatic == ZSTD_cwksp_dynamic_alloc) {
|
|
376
|
+
/* We need to keep the redzone poisoned while unpoisoning the bytes that
|
|
377
|
+
* are actually allocated. */
|
|
378
|
+
__asan_unpoison_memory_region(alloc, bytes - 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE);
|
|
379
|
+
}
|
|
272
380
|
}
|
|
273
381
|
#endif
|
|
274
382
|
|
|
@@ -278,33 +386,78 @@ MEM_STATIC void* ZSTD_cwksp_reserve_internal(
|
|
|
278
386
|
/**
|
|
279
387
|
* Reserves and returns unaligned memory.
|
|
280
388
|
*/
|
|
281
|
-
MEM_STATIC BYTE* ZSTD_cwksp_reserve_buffer(ZSTD_cwksp* ws, size_t bytes)
|
|
389
|
+
MEM_STATIC BYTE* ZSTD_cwksp_reserve_buffer(ZSTD_cwksp* ws, size_t bytes)
|
|
390
|
+
{
|
|
282
391
|
return (BYTE*)ZSTD_cwksp_reserve_internal(ws, bytes, ZSTD_cwksp_alloc_buffers);
|
|
283
392
|
}
|
|
284
393
|
|
|
285
394
|
/**
|
|
286
|
-
* Reserves and returns memory sized on and aligned on
|
|
395
|
+
* Reserves and returns memory sized on and aligned on ZSTD_CWKSP_ALIGNMENT_BYTES (64 bytes).
|
|
396
|
+
* This memory has been initialized at least once in the past.
|
|
397
|
+
* This doesn't mean it has been initialized this time, and it might contain data from previous
|
|
398
|
+
* operations.
|
|
399
|
+
* The main usage is for algorithms that might need read access into uninitialized memory.
|
|
400
|
+
* The algorithm must maintain safety under these conditions and must make sure it doesn't
|
|
401
|
+
* leak any of the past data (directly or in side channels).
|
|
287
402
|
*/
|
|
288
|
-
MEM_STATIC void*
|
|
289
|
-
|
|
290
|
-
|
|
403
|
+
MEM_STATIC void* ZSTD_cwksp_reserve_aligned_init_once(ZSTD_cwksp* ws, size_t bytes)
|
|
404
|
+
{
|
|
405
|
+
size_t const alignedBytes = ZSTD_cwksp_align(bytes, ZSTD_CWKSP_ALIGNMENT_BYTES);
|
|
406
|
+
void* ptr = ZSTD_cwksp_reserve_internal(ws, alignedBytes, ZSTD_cwksp_alloc_aligned_init_once);
|
|
407
|
+
assert(((size_t)ptr & (ZSTD_CWKSP_ALIGNMENT_BYTES-1))== 0);
|
|
408
|
+
if(ptr && ptr < ws->initOnceStart) {
|
|
409
|
+
/* We assume the memory following the current allocation is either:
|
|
410
|
+
* 1. Not usable as initOnce memory (end of workspace)
|
|
411
|
+
* 2. Another initOnce buffer that has been allocated before (and so was previously memset)
|
|
412
|
+
* 3. An ASAN redzone, in which case we don't want to write on it
|
|
413
|
+
* For these reasons it should be fine to not explicitly zero every byte up to ws->initOnceStart.
|
|
414
|
+
* Note that we assume here that MSAN and ASAN cannot run in the same time. */
|
|
415
|
+
ZSTD_memset(ptr, 0, MIN((size_t)((U8*)ws->initOnceStart - (U8*)ptr), alignedBytes));
|
|
416
|
+
ws->initOnceStart = ptr;
|
|
417
|
+
}
|
|
418
|
+
#if ZSTD_MEMORY_SANITIZER
|
|
419
|
+
assert(__msan_test_shadow(ptr, bytes) == -1);
|
|
420
|
+
#endif
|
|
421
|
+
return ptr;
|
|
291
422
|
}
|
|
292
423
|
|
|
293
424
|
/**
|
|
294
|
-
*
|
|
295
|
-
|
|
425
|
+
* Reserves and returns memory sized on and aligned on ZSTD_CWKSP_ALIGNMENT_BYTES (64 bytes).
|
|
426
|
+
*/
|
|
427
|
+
MEM_STATIC void* ZSTD_cwksp_reserve_aligned(ZSTD_cwksp* ws, size_t bytes)
|
|
428
|
+
{
|
|
429
|
+
void* ptr = ZSTD_cwksp_reserve_internal(ws, ZSTD_cwksp_align(bytes, ZSTD_CWKSP_ALIGNMENT_BYTES),
|
|
430
|
+
ZSTD_cwksp_alloc_aligned);
|
|
431
|
+
assert(((size_t)ptr & (ZSTD_CWKSP_ALIGNMENT_BYTES-1))== 0);
|
|
432
|
+
return ptr;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Aligned on 64 bytes. These buffers have the special property that
|
|
437
|
+
* their values remain constrained, allowing us to reuse them without
|
|
296
438
|
* memset()-ing them.
|
|
297
439
|
*/
|
|
298
|
-
MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes)
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
void*
|
|
302
|
-
void*
|
|
440
|
+
MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes)
|
|
441
|
+
{
|
|
442
|
+
const ZSTD_cwksp_alloc_phase_e phase = ZSTD_cwksp_alloc_aligned_init_once;
|
|
443
|
+
void* alloc;
|
|
444
|
+
void* end;
|
|
445
|
+
void* top;
|
|
446
|
+
|
|
447
|
+
/* We can only start allocating tables after we are done reserving space for objects at the
|
|
448
|
+
* start of the workspace */
|
|
449
|
+
if(ws->phase < phase) {
|
|
450
|
+
if (ZSTD_isError(ZSTD_cwksp_internal_advance_phase(ws, phase))) {
|
|
451
|
+
return NULL;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
alloc = ws->tableEnd;
|
|
455
|
+
end = (BYTE *)alloc + bytes;
|
|
456
|
+
top = ws->allocStart;
|
|
303
457
|
|
|
304
458
|
DEBUGLOG(5, "cwksp: reserving %p table %zd bytes, %zd bytes remaining",
|
|
305
459
|
alloc, bytes, ZSTD_cwksp_available_space(ws) - bytes);
|
|
306
460
|
assert((bytes & (sizeof(U32)-1)) == 0);
|
|
307
|
-
ZSTD_cwksp_internal_advance_phase(ws, phase);
|
|
308
461
|
ZSTD_cwksp_assert_internal_consistency(ws);
|
|
309
462
|
assert(end <= top);
|
|
310
463
|
if (end > top) {
|
|
@@ -320,14 +473,18 @@ MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes) {
|
|
|
320
473
|
}
|
|
321
474
|
#endif
|
|
322
475
|
|
|
476
|
+
assert((bytes & (ZSTD_CWKSP_ALIGNMENT_BYTES-1)) == 0);
|
|
477
|
+
assert(((size_t)alloc & (ZSTD_CWKSP_ALIGNMENT_BYTES-1))== 0);
|
|
323
478
|
return alloc;
|
|
324
479
|
}
|
|
325
480
|
|
|
326
481
|
/**
|
|
327
482
|
* Aligned on sizeof(void*).
|
|
483
|
+
* Note : should happen only once, at workspace first initialization
|
|
328
484
|
*/
|
|
329
|
-
MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes)
|
|
330
|
-
|
|
485
|
+
MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes)
|
|
486
|
+
{
|
|
487
|
+
size_t const roundedBytes = ZSTD_cwksp_align(bytes, sizeof(void*));
|
|
331
488
|
void* alloc = ws->objectEnd;
|
|
332
489
|
void* end = (BYTE*)alloc + roundedBytes;
|
|
333
490
|
|
|
@@ -336,15 +493,15 @@ MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) {
|
|
|
336
493
|
end = (BYTE *)end + 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE;
|
|
337
494
|
#endif
|
|
338
495
|
|
|
339
|
-
DEBUGLOG(
|
|
496
|
+
DEBUGLOG(4,
|
|
340
497
|
"cwksp: reserving %p object %zd bytes (rounded to %zd), %zd bytes remaining",
|
|
341
498
|
alloc, bytes, roundedBytes, ZSTD_cwksp_available_space(ws) - roundedBytes);
|
|
342
|
-
assert((
|
|
343
|
-
assert(
|
|
499
|
+
assert((size_t)alloc % ZSTD_ALIGNOF(void*) == 0);
|
|
500
|
+
assert(bytes % ZSTD_ALIGNOF(void*) == 0);
|
|
344
501
|
ZSTD_cwksp_assert_internal_consistency(ws);
|
|
345
502
|
/* we must be in the first phase, no advance is possible */
|
|
346
503
|
if (ws->phase != ZSTD_cwksp_alloc_objects || end > ws->workspaceEnd) {
|
|
347
|
-
DEBUGLOG(
|
|
504
|
+
DEBUGLOG(3, "cwksp: object alloc failed!");
|
|
348
505
|
ws->allocFailed = 1;
|
|
349
506
|
return NULL;
|
|
350
507
|
}
|
|
@@ -355,7 +512,7 @@ MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) {
|
|
|
355
512
|
#if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
|
|
356
513
|
/* Move alloc so there's ZSTD_CWKSP_ASAN_REDZONE_SIZE unused space on
|
|
357
514
|
* either size. */
|
|
358
|
-
alloc = (BYTE
|
|
515
|
+
alloc = (BYTE*)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE;
|
|
359
516
|
if (ws->isStatic == ZSTD_cwksp_dynamic_alloc) {
|
|
360
517
|
__asan_unpoison_memory_region(alloc, bytes);
|
|
361
518
|
}
|
|
@@ -364,17 +521,26 @@ MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) {
|
|
|
364
521
|
return alloc;
|
|
365
522
|
}
|
|
366
523
|
|
|
367
|
-
MEM_STATIC void ZSTD_cwksp_mark_tables_dirty(ZSTD_cwksp* ws)
|
|
524
|
+
MEM_STATIC void ZSTD_cwksp_mark_tables_dirty(ZSTD_cwksp* ws)
|
|
525
|
+
{
|
|
368
526
|
DEBUGLOG(4, "cwksp: ZSTD_cwksp_mark_tables_dirty");
|
|
369
527
|
|
|
370
528
|
#if ZSTD_MEMORY_SANITIZER && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE)
|
|
371
|
-
/* To validate that the table
|
|
529
|
+
/* To validate that the table reuse logic is sound, and that we don't
|
|
372
530
|
* access table space that we haven't cleaned, we re-"poison" the table
|
|
373
|
-
* space every time we mark it dirty.
|
|
531
|
+
* space every time we mark it dirty.
|
|
532
|
+
* Since tableValidEnd space and initOnce space may overlap we don't poison
|
|
533
|
+
* the initOnce portion as it break its promise. This means that this poisoning
|
|
534
|
+
* check isn't always applied fully. */
|
|
374
535
|
{
|
|
375
536
|
size_t size = (BYTE*)ws->tableValidEnd - (BYTE*)ws->objectEnd;
|
|
376
537
|
assert(__msan_test_shadow(ws->objectEnd, size) == -1);
|
|
377
|
-
|
|
538
|
+
if((BYTE*)ws->tableValidEnd < (BYTE*)ws->initOnceStart) {
|
|
539
|
+
__msan_poison(ws->objectEnd, size);
|
|
540
|
+
} else {
|
|
541
|
+
assert(ws->initOnceStart >= ws->objectEnd);
|
|
542
|
+
__msan_poison(ws->objectEnd, (BYTE*)ws->initOnceStart - (BYTE*)ws->objectEnd);
|
|
543
|
+
}
|
|
378
544
|
}
|
|
379
545
|
#endif
|
|
380
546
|
|
|
@@ -402,7 +568,7 @@ MEM_STATIC void ZSTD_cwksp_clean_tables(ZSTD_cwksp* ws) {
|
|
|
402
568
|
assert(ws->tableValidEnd >= ws->objectEnd);
|
|
403
569
|
assert(ws->tableValidEnd <= ws->allocStart);
|
|
404
570
|
if (ws->tableValidEnd < ws->tableEnd) {
|
|
405
|
-
ZSTD_memset(ws->tableValidEnd, 0, (BYTE*)ws->tableEnd - (BYTE*)ws->tableValidEnd);
|
|
571
|
+
ZSTD_memset(ws->tableValidEnd, 0, (size_t)((BYTE*)ws->tableEnd - (BYTE*)ws->tableValidEnd));
|
|
406
572
|
}
|
|
407
573
|
ZSTD_cwksp_mark_tables_clean(ws);
|
|
408
574
|
}
|
|
@@ -437,13 +603,16 @@ MEM_STATIC void ZSTD_cwksp_clear(ZSTD_cwksp* ws) {
|
|
|
437
603
|
DEBUGLOG(4, "cwksp: clearing!");
|
|
438
604
|
|
|
439
605
|
#if ZSTD_MEMORY_SANITIZER && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE)
|
|
440
|
-
/* To validate that the context
|
|
606
|
+
/* To validate that the context reuse logic is sound, and that we don't
|
|
441
607
|
* access stuff that this compression hasn't initialized, we re-"poison"
|
|
442
|
-
* the workspace
|
|
443
|
-
*
|
|
608
|
+
* the workspace except for the areas in which we expect memory reuse
|
|
609
|
+
* without initialization (objects, valid tables area and init once
|
|
610
|
+
* memory). */
|
|
444
611
|
{
|
|
445
|
-
|
|
446
|
-
|
|
612
|
+
if((BYTE*)ws->tableValidEnd < (BYTE*)ws->initOnceStart) {
|
|
613
|
+
size_t size = (BYTE*)ws->initOnceStart - (BYTE*)ws->tableValidEnd;
|
|
614
|
+
__msan_poison(ws->tableValidEnd, size);
|
|
615
|
+
}
|
|
447
616
|
}
|
|
448
617
|
#endif
|
|
449
618
|
|
|
@@ -459,14 +628,23 @@ MEM_STATIC void ZSTD_cwksp_clear(ZSTD_cwksp* ws) {
|
|
|
459
628
|
#endif
|
|
460
629
|
|
|
461
630
|
ws->tableEnd = ws->objectEnd;
|
|
462
|
-
ws->allocStart = ws
|
|
631
|
+
ws->allocStart = ZSTD_cwksp_initialAllocStart(ws);
|
|
463
632
|
ws->allocFailed = 0;
|
|
464
|
-
if (ws->phase >
|
|
465
|
-
ws->phase =
|
|
633
|
+
if (ws->phase > ZSTD_cwksp_alloc_aligned_init_once) {
|
|
634
|
+
ws->phase = ZSTD_cwksp_alloc_aligned_init_once;
|
|
466
635
|
}
|
|
467
636
|
ZSTD_cwksp_assert_internal_consistency(ws);
|
|
468
637
|
}
|
|
469
638
|
|
|
639
|
+
MEM_STATIC size_t ZSTD_cwksp_sizeof(const ZSTD_cwksp* ws) {
|
|
640
|
+
return (size_t)((BYTE*)ws->workspaceEnd - (BYTE*)ws->workspace);
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
MEM_STATIC size_t ZSTD_cwksp_used(const ZSTD_cwksp* ws) {
|
|
644
|
+
return (size_t)((BYTE*)ws->tableEnd - (BYTE*)ws->workspace)
|
|
645
|
+
+ (size_t)((BYTE*)ws->workspaceEnd - (BYTE*)ws->allocStart);
|
|
646
|
+
}
|
|
647
|
+
|
|
470
648
|
/**
|
|
471
649
|
* The provided workspace takes ownership of the buffer [start, start+size).
|
|
472
650
|
* Any existing values in the workspace are ignored (the previously managed
|
|
@@ -479,6 +657,7 @@ MEM_STATIC void ZSTD_cwksp_init(ZSTD_cwksp* ws, void* start, size_t size, ZSTD_c
|
|
|
479
657
|
ws->workspaceEnd = (BYTE*)start + size;
|
|
480
658
|
ws->objectEnd = ws->workspace;
|
|
481
659
|
ws->tableValidEnd = ws->objectEnd;
|
|
660
|
+
ws->initOnceStart = ZSTD_cwksp_initialAllocStart(ws);
|
|
482
661
|
ws->phase = ZSTD_cwksp_alloc_objects;
|
|
483
662
|
ws->isStatic = isStatic;
|
|
484
663
|
ZSTD_cwksp_clear(ws);
|
|
@@ -497,28 +676,24 @@ MEM_STATIC size_t ZSTD_cwksp_create(ZSTD_cwksp* ws, size_t size, ZSTD_customMem
|
|
|
497
676
|
MEM_STATIC void ZSTD_cwksp_free(ZSTD_cwksp* ws, ZSTD_customMem customMem) {
|
|
498
677
|
void *ptr = ws->workspace;
|
|
499
678
|
DEBUGLOG(4, "cwksp: freeing workspace");
|
|
679
|
+
#if ZSTD_MEMORY_SANITIZER && !defined(ZSTD_MSAN_DONT_POISON_WORKSPACE)
|
|
680
|
+
if (ptr != NULL && customMem.customFree != NULL) {
|
|
681
|
+
__msan_unpoison(ptr, ZSTD_cwksp_sizeof(ws));
|
|
682
|
+
}
|
|
683
|
+
#endif
|
|
500
684
|
ZSTD_memset(ws, 0, sizeof(ZSTD_cwksp));
|
|
501
685
|
ZSTD_customFree(ptr, customMem);
|
|
502
686
|
}
|
|
503
687
|
|
|
504
688
|
/**
|
|
505
689
|
* Moves the management of a workspace from one cwksp to another. The src cwksp
|
|
506
|
-
* is left in an invalid state (src must be re-init()'ed before
|
|
690
|
+
* is left in an invalid state (src must be re-init()'ed before it's used again).
|
|
507
691
|
*/
|
|
508
692
|
MEM_STATIC void ZSTD_cwksp_move(ZSTD_cwksp* dst, ZSTD_cwksp* src) {
|
|
509
693
|
*dst = *src;
|
|
510
694
|
ZSTD_memset(src, 0, sizeof(ZSTD_cwksp));
|
|
511
695
|
}
|
|
512
696
|
|
|
513
|
-
MEM_STATIC size_t ZSTD_cwksp_sizeof(const ZSTD_cwksp* ws) {
|
|
514
|
-
return (size_t)((BYTE*)ws->workspaceEnd - (BYTE*)ws->workspace);
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
MEM_STATIC size_t ZSTD_cwksp_used(const ZSTD_cwksp* ws) {
|
|
518
|
-
return (size_t)((BYTE*)ws->tableEnd - (BYTE*)ws->workspace)
|
|
519
|
-
+ (size_t)((BYTE*)ws->workspaceEnd - (BYTE*)ws->allocStart);
|
|
520
|
-
}
|
|
521
|
-
|
|
522
697
|
MEM_STATIC int ZSTD_cwksp_reserve_failed(const ZSTD_cwksp* ws) {
|
|
523
698
|
return ws->allocFailed;
|
|
524
699
|
}
|
|
@@ -527,6 +702,18 @@ MEM_STATIC int ZSTD_cwksp_reserve_failed(const ZSTD_cwksp* ws) {
|
|
|
527
702
|
* Functions Checking Free Space
|
|
528
703
|
***************************************/
|
|
529
704
|
|
|
705
|
+
/* ZSTD_alignmentSpaceWithinBounds() :
|
|
706
|
+
* Returns if the estimated space needed for a wksp is within an acceptable limit of the
|
|
707
|
+
* actual amount of space used.
|
|
708
|
+
*/
|
|
709
|
+
MEM_STATIC int ZSTD_cwksp_estimated_space_within_bounds(const ZSTD_cwksp *const ws, size_t const estimatedSpace) {
|
|
710
|
+
/* We have an alignment space between objects and tables between tables and buffers, so we can have up to twice
|
|
711
|
+
* the alignment bytes difference between estimation and actual usage */
|
|
712
|
+
return (estimatedSpace - ZSTD_cwksp_slack_space_required()) <= ZSTD_cwksp_used(ws) &&
|
|
713
|
+
ZSTD_cwksp_used(ws) <= estimatedSpace;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
|
|
530
717
|
MEM_STATIC size_t ZSTD_cwksp_available_space(ZSTD_cwksp* ws) {
|
|
531
718
|
return (size_t)((BYTE*)ws->allocStart - (BYTE*)ws->tableEnd);
|
|
532
719
|
}
|