extzstd 0.3.2 → 0.3.3

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.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/contrib/zstd/CHANGELOG +188 -1
  4. data/contrib/zstd/CONTRIBUTING.md +157 -74
  5. data/contrib/zstd/LICENSE +4 -4
  6. data/contrib/zstd/Makefile +81 -58
  7. data/contrib/zstd/Package.swift +36 -0
  8. data/contrib/zstd/README.md +59 -35
  9. data/contrib/zstd/TESTING.md +2 -3
  10. data/contrib/zstd/appveyor.yml +49 -136
  11. data/contrib/zstd/lib/BUCK +5 -7
  12. data/contrib/zstd/lib/Makefile +87 -181
  13. data/contrib/zstd/lib/README.md +23 -6
  14. data/contrib/zstd/lib/common/allocations.h +55 -0
  15. data/contrib/zstd/lib/common/bits.h +200 -0
  16. data/contrib/zstd/lib/common/bitstream.h +33 -59
  17. data/contrib/zstd/lib/common/compiler.h +115 -45
  18. data/contrib/zstd/lib/common/cpu.h +1 -1
  19. data/contrib/zstd/lib/common/debug.c +1 -1
  20. data/contrib/zstd/lib/common/debug.h +1 -1
  21. data/contrib/zstd/lib/common/entropy_common.c +15 -37
  22. data/contrib/zstd/lib/common/error_private.c +9 -2
  23. data/contrib/zstd/lib/common/error_private.h +82 -3
  24. data/contrib/zstd/lib/common/fse.h +9 -85
  25. data/contrib/zstd/lib/common/fse_decompress.c +29 -111
  26. data/contrib/zstd/lib/common/huf.h +84 -172
  27. data/contrib/zstd/lib/common/mem.h +58 -49
  28. data/contrib/zstd/lib/common/pool.c +37 -16
  29. data/contrib/zstd/lib/common/pool.h +9 -3
  30. data/contrib/zstd/lib/common/portability_macros.h +156 -0
  31. data/contrib/zstd/lib/common/threading.c +68 -14
  32. data/contrib/zstd/lib/common/threading.h +5 -10
  33. data/contrib/zstd/lib/common/xxhash.c +7 -809
  34. data/contrib/zstd/lib/common/xxhash.h +5568 -167
  35. data/contrib/zstd/lib/common/zstd_common.c +1 -36
  36. data/contrib/zstd/lib/common/zstd_deps.h +1 -1
  37. data/contrib/zstd/lib/common/zstd_internal.h +64 -150
  38. data/contrib/zstd/lib/common/zstd_trace.h +163 -0
  39. data/contrib/zstd/lib/compress/clevels.h +134 -0
  40. data/contrib/zstd/lib/compress/fse_compress.c +69 -150
  41. data/contrib/zstd/lib/compress/hist.c +1 -1
  42. data/contrib/zstd/lib/compress/hist.h +1 -1
  43. data/contrib/zstd/lib/compress/huf_compress.c +773 -251
  44. data/contrib/zstd/lib/compress/zstd_compress.c +2650 -826
  45. data/contrib/zstd/lib/compress/zstd_compress_internal.h +509 -180
  46. data/contrib/zstd/lib/compress/zstd_compress_literals.c +117 -40
  47. data/contrib/zstd/lib/compress/zstd_compress_literals.h +16 -6
  48. data/contrib/zstd/lib/compress/zstd_compress_sequences.c +28 -19
  49. data/contrib/zstd/lib/compress/zstd_compress_sequences.h +1 -1
  50. data/contrib/zstd/lib/compress/zstd_compress_superblock.c +33 -305
  51. data/contrib/zstd/lib/compress/zstd_compress_superblock.h +1 -1
  52. data/contrib/zstd/lib/compress/zstd_cwksp.h +266 -85
  53. data/contrib/zstd/lib/compress/zstd_double_fast.c +369 -132
  54. data/contrib/zstd/lib/compress/zstd_double_fast.h +3 -2
  55. data/contrib/zstd/lib/compress/zstd_fast.c +722 -258
  56. data/contrib/zstd/lib/compress/zstd_fast.h +3 -2
  57. data/contrib/zstd/lib/compress/zstd_lazy.c +1105 -360
  58. data/contrib/zstd/lib/compress/zstd_lazy.h +41 -1
  59. data/contrib/zstd/lib/compress/zstd_ldm.c +272 -208
  60. data/contrib/zstd/lib/compress/zstd_ldm.h +3 -2
  61. data/contrib/zstd/lib/compress/zstd_ldm_geartab.h +106 -0
  62. data/contrib/zstd/lib/compress/zstd_opt.c +324 -197
  63. data/contrib/zstd/lib/compress/zstd_opt.h +1 -1
  64. data/contrib/zstd/lib/compress/zstdmt_compress.c +109 -53
  65. data/contrib/zstd/lib/compress/zstdmt_compress.h +9 -6
  66. data/contrib/zstd/lib/decompress/huf_decompress.c +1071 -539
  67. data/contrib/zstd/lib/decompress/huf_decompress_amd64.S +576 -0
  68. data/contrib/zstd/lib/decompress/zstd_ddict.c +4 -4
  69. data/contrib/zstd/lib/decompress/zstd_ddict.h +1 -1
  70. data/contrib/zstd/lib/decompress/zstd_decompress.c +507 -82
  71. data/contrib/zstd/lib/decompress/zstd_decompress_block.c +962 -310
  72. data/contrib/zstd/lib/decompress/zstd_decompress_block.h +14 -3
  73. data/contrib/zstd/lib/decompress/zstd_decompress_internal.h +54 -6
  74. data/contrib/zstd/lib/deprecated/zbuff.h +1 -1
  75. data/contrib/zstd/lib/deprecated/zbuff_common.c +1 -1
  76. data/contrib/zstd/lib/deprecated/zbuff_compress.c +24 -4
  77. data/contrib/zstd/lib/deprecated/zbuff_decompress.c +3 -1
  78. data/contrib/zstd/lib/dictBuilder/cover.c +44 -32
  79. data/contrib/zstd/lib/dictBuilder/cover.h +6 -5
  80. data/contrib/zstd/lib/dictBuilder/divsufsort.c +1 -1
  81. data/contrib/zstd/lib/dictBuilder/fastcover.c +24 -16
  82. data/contrib/zstd/lib/dictBuilder/zdict.c +88 -95
  83. data/contrib/zstd/lib/legacy/zstd_legacy.h +8 -1
  84. data/contrib/zstd/lib/legacy/zstd_v01.c +16 -53
  85. data/contrib/zstd/lib/legacy/zstd_v01.h +1 -1
  86. data/contrib/zstd/lib/legacy/zstd_v02.c +24 -69
  87. data/contrib/zstd/lib/legacy/zstd_v02.h +1 -1
  88. data/contrib/zstd/lib/legacy/zstd_v03.c +25 -72
  89. data/contrib/zstd/lib/legacy/zstd_v03.h +1 -1
  90. data/contrib/zstd/lib/legacy/zstd_v04.c +23 -69
  91. data/contrib/zstd/lib/legacy/zstd_v04.h +1 -1
  92. data/contrib/zstd/lib/legacy/zstd_v05.c +35 -85
  93. data/contrib/zstd/lib/legacy/zstd_v05.h +1 -1
  94. data/contrib/zstd/lib/legacy/zstd_v06.c +42 -87
  95. data/contrib/zstd/lib/legacy/zstd_v06.h +1 -1
  96. data/contrib/zstd/lib/legacy/zstd_v07.c +35 -82
  97. data/contrib/zstd/lib/legacy/zstd_v07.h +1 -1
  98. data/contrib/zstd/lib/libzstd.mk +214 -0
  99. data/contrib/zstd/lib/libzstd.pc.in +4 -3
  100. data/contrib/zstd/lib/module.modulemap +35 -0
  101. data/contrib/zstd/lib/{dictBuilder/zdict.h → zdict.h} +202 -33
  102. data/contrib/zstd/lib/zstd.h +922 -293
  103. data/contrib/zstd/lib/{common/zstd_errors.h → zstd_errors.h} +27 -8
  104. data/ext/extconf.rb +7 -6
  105. data/ext/extzstd.c +13 -10
  106. data/ext/libzstd_conf.h +0 -1
  107. data/ext/zstd_decompress_asm.S +1 -0
  108. metadata +16 -5
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
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
- ZSTD_cwksp_alloc_buffers,
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 ... ->] free space [<- ... aligned][<- ... buffers]
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.
128
+ *
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.
121
136
  *
122
- * - Aligned: these buffers are used for various purposes that require 4 byte
123
- * alignment, but don't require any initialization before they're used.
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. Buffers
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,20 @@ 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
+ #if defined(ZSTD_MSAN_PRINT)
196
+ if(offset!=-1) {
197
+ __msan_print_shadow((U8*)ws->initOnceStart + offset - 8, 32);
198
+ }
199
+ #endif
200
+ assert(offset==-1);
201
+ };
202
+ #endif
170
203
  }
171
204
 
172
205
  /**
@@ -187,6 +220,8 @@ MEM_STATIC size_t ZSTD_cwksp_align(size_t size, size_t const align) {
187
220
  * Since tables aren't currently redzoned, you don't need to call through this
188
221
  * to figure out how much space you need for the matchState tables. Everything
189
222
  * else is though.
223
+ *
224
+ * Do not use for sizing aligned buffers. Instead, use ZSTD_cwksp_aligned_alloc_size().
190
225
  */
191
226
  MEM_STATIC size_t ZSTD_cwksp_alloc_size(size_t size) {
192
227
  if (size == 0)
@@ -198,77 +233,149 @@ MEM_STATIC size_t ZSTD_cwksp_alloc_size(size_t size) {
198
233
  #endif
199
234
  }
200
235
 
201
- MEM_STATIC void ZSTD_cwksp_internal_advance_phase(
202
- ZSTD_cwksp* ws, ZSTD_cwksp_alloc_phase_e phase) {
236
+ /**
237
+ * Returns an adjusted alloc size that is the nearest larger multiple of 64 bytes.
238
+ * Used to determine the number of bytes required for a given "aligned".
239
+ */
240
+ MEM_STATIC size_t ZSTD_cwksp_aligned_alloc_size(size_t size) {
241
+ return ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(size, ZSTD_CWKSP_ALIGNMENT_BYTES));
242
+ }
243
+
244
+ /**
245
+ * Returns the amount of additional space the cwksp must allocate
246
+ * for internal purposes (currently only alignment).
247
+ */
248
+ MEM_STATIC size_t ZSTD_cwksp_slack_space_required(void) {
249
+ /* For alignment, the wksp will always allocate an additional 2*ZSTD_CWKSP_ALIGNMENT_BYTES
250
+ * bytes to align the beginning of tables section and end of buffers;
251
+ */
252
+ size_t const slackSpace = ZSTD_CWKSP_ALIGNMENT_BYTES * 2;
253
+ return slackSpace;
254
+ }
255
+
256
+
257
+ /**
258
+ * Return the number of additional bytes required to align a pointer to the given number of bytes.
259
+ * alignBytes must be a power of two.
260
+ */
261
+ MEM_STATIC size_t ZSTD_cwksp_bytes_to_align_ptr(void* ptr, const size_t alignBytes) {
262
+ size_t const alignBytesMask = alignBytes - 1;
263
+ size_t const bytes = (alignBytes - ((size_t)ptr & (alignBytesMask))) & alignBytesMask;
264
+ assert((alignBytes & alignBytesMask) == 0);
265
+ assert(bytes < alignBytes);
266
+ return bytes;
267
+ }
268
+
269
+ /**
270
+ * Returns the initial value for allocStart which is used to determine the position from
271
+ * which we can allocate from the end of the workspace.
272
+ */
273
+ MEM_STATIC void* ZSTD_cwksp_initialAllocStart(ZSTD_cwksp* ws) {
274
+ return (void*)((size_t)ws->workspaceEnd & ~(ZSTD_CWKSP_ALIGNMENT_BYTES-1));
275
+ }
276
+
277
+ /**
278
+ * Internal function. Do not use directly.
279
+ * Reserves the given number of bytes within the aligned/buffer segment of the wksp,
280
+ * which counts from the end of the wksp (as opposed to the object/table segment).
281
+ *
282
+ * Returns a pointer to the beginning of that space.
283
+ */
284
+ MEM_STATIC void*
285
+ ZSTD_cwksp_reserve_internal_buffer_space(ZSTD_cwksp* ws, size_t const bytes)
286
+ {
287
+ void* const alloc = (BYTE*)ws->allocStart - bytes;
288
+ void* const bottom = ws->tableEnd;
289
+ DEBUGLOG(5, "cwksp: reserving %p %zd bytes, %zd bytes remaining",
290
+ alloc, bytes, ZSTD_cwksp_available_space(ws) - bytes);
291
+ ZSTD_cwksp_assert_internal_consistency(ws);
292
+ assert(alloc >= bottom);
293
+ if (alloc < bottom) {
294
+ DEBUGLOG(4, "cwksp: alloc failed!");
295
+ ws->allocFailed = 1;
296
+ return NULL;
297
+ }
298
+ /* the area is reserved from the end of wksp.
299
+ * If it overlaps with tableValidEnd, it voids guarantees on values' range */
300
+ if (alloc < ws->tableValidEnd) {
301
+ ws->tableValidEnd = alloc;
302
+ }
303
+ ws->allocStart = alloc;
304
+ return alloc;
305
+ }
306
+
307
+ /**
308
+ * Moves the cwksp to the next phase, and does any necessary allocations.
309
+ * cwksp initialization must necessarily go through each phase in order.
310
+ * Returns a 0 on success, or zstd error
311
+ */
312
+ MEM_STATIC size_t
313
+ ZSTD_cwksp_internal_advance_phase(ZSTD_cwksp* ws, ZSTD_cwksp_alloc_phase_e phase)
314
+ {
203
315
  assert(phase >= ws->phase);
204
316
  if (phase > ws->phase) {
205
- if (ws->phase < ZSTD_cwksp_alloc_buffers &&
206
- phase >= ZSTD_cwksp_alloc_buffers) {
317
+ /* Going from allocating objects to allocating initOnce / tables */
318
+ if (ws->phase < ZSTD_cwksp_alloc_aligned_init_once &&
319
+ phase >= ZSTD_cwksp_alloc_aligned_init_once) {
207
320
  ws->tableValidEnd = ws->objectEnd;
208
- }
209
- if (ws->phase < ZSTD_cwksp_alloc_aligned &&
210
- phase >= ZSTD_cwksp_alloc_aligned) {
211
- /* If unaligned allocations down from a too-large top have left us
212
- * unaligned, we need to realign our alloc ptr. Technically, this
213
- * can consume space that is unaccounted for in the neededSpace
214
- * calculation. However, I believe this can only happen when the
215
- * workspace is too large, and specifically when it is too large
216
- * by a larger margin than the space that will be consumed. */
217
- /* TODO: cleaner, compiler warning friendly way to do this??? */
218
- ws->allocStart = (BYTE*)ws->allocStart - ((size_t)ws->allocStart & (sizeof(U32)-1));
219
- if (ws->allocStart < ws->tableValidEnd) {
220
- ws->tableValidEnd = ws->allocStart;
321
+ ws->initOnceStart = ZSTD_cwksp_initialAllocStart(ws);
322
+
323
+ { /* Align the start of the tables to 64 bytes. Use [0, 63] bytes */
324
+ void *const alloc = ws->objectEnd;
325
+ size_t const bytesToAlign = ZSTD_cwksp_bytes_to_align_ptr(alloc, ZSTD_CWKSP_ALIGNMENT_BYTES);
326
+ void *const objectEnd = (BYTE *) alloc + bytesToAlign;
327
+ DEBUGLOG(5, "reserving table alignment addtl space: %zu", bytesToAlign);
328
+ RETURN_ERROR_IF(objectEnd > ws->workspaceEnd, memory_allocation,
329
+ "table phase - alignment initial allocation failed!");
330
+ ws->objectEnd = objectEnd;
331
+ ws->tableEnd = objectEnd; /* table area starts being empty */
332
+ if (ws->tableValidEnd < ws->tableEnd) {
333
+ ws->tableValidEnd = ws->tableEnd;
334
+ }
221
335
  }
222
336
  }
223
337
  ws->phase = phase;
338
+ ZSTD_cwksp_assert_internal_consistency(ws);
224
339
  }
340
+ return 0;
225
341
  }
226
342
 
227
343
  /**
228
344
  * Returns whether this object/buffer/etc was allocated in this workspace.
229
345
  */
230
- MEM_STATIC int ZSTD_cwksp_owns_buffer(const ZSTD_cwksp* ws, const void* ptr) {
231
- return (ptr != NULL) && (ws->workspace <= ptr) && (ptr <= ws->workspaceEnd);
346
+ MEM_STATIC int ZSTD_cwksp_owns_buffer(const ZSTD_cwksp* ws, const void* ptr)
347
+ {
348
+ return (ptr != NULL) && (ws->workspace <= ptr) && (ptr < ws->workspaceEnd);
232
349
  }
233
350
 
234
351
  /**
235
352
  * Internal function. Do not use directly.
236
353
  */
237
- MEM_STATIC void* ZSTD_cwksp_reserve_internal(
238
- ZSTD_cwksp* ws, size_t bytes, ZSTD_cwksp_alloc_phase_e phase) {
354
+ MEM_STATIC void*
355
+ ZSTD_cwksp_reserve_internal(ZSTD_cwksp* ws, size_t bytes, ZSTD_cwksp_alloc_phase_e phase)
356
+ {
239
357
  void* alloc;
240
- void* bottom = ws->tableEnd;
241
- ZSTD_cwksp_internal_advance_phase(ws, phase);
242
- alloc = (BYTE *)ws->allocStart - bytes;
243
-
244
- if (bytes == 0)
358
+ if (ZSTD_isError(ZSTD_cwksp_internal_advance_phase(ws, phase)) || bytes == 0) {
245
359
  return NULL;
360
+ }
246
361
 
247
362
  #if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
248
363
  /* over-reserve space */
249
- alloc = (BYTE *)alloc - 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE;
364
+ bytes += 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE;
250
365
  #endif
251
366
 
252
- DEBUGLOG(5, "cwksp: reserving %p %zd bytes, %zd bytes remaining",
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;
367
+ alloc = ZSTD_cwksp_reserve_internal_buffer_space(ws, bytes);
265
368
 
266
369
  #if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
267
370
  /* Move alloc so there's ZSTD_CWKSP_ASAN_REDZONE_SIZE unused space on
268
371
  * either size. */
269
- alloc = (BYTE *)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE;
270
- if (ws->isStatic == ZSTD_cwksp_dynamic_alloc) {
271
- __asan_unpoison_memory_region(alloc, bytes);
372
+ if (alloc) {
373
+ alloc = (BYTE *)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE;
374
+ if (ws->isStatic == ZSTD_cwksp_dynamic_alloc) {
375
+ /* We need to keep the redzone poisoned while unpoisoning the bytes that
376
+ * are actually allocated. */
377
+ __asan_unpoison_memory_region(alloc, bytes - 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE);
378
+ }
272
379
  }
273
380
  #endif
274
381
 
@@ -278,33 +385,78 @@ MEM_STATIC void* ZSTD_cwksp_reserve_internal(
278
385
  /**
279
386
  * Reserves and returns unaligned memory.
280
387
  */
281
- MEM_STATIC BYTE* ZSTD_cwksp_reserve_buffer(ZSTD_cwksp* ws, size_t bytes) {
388
+ MEM_STATIC BYTE* ZSTD_cwksp_reserve_buffer(ZSTD_cwksp* ws, size_t bytes)
389
+ {
282
390
  return (BYTE*)ZSTD_cwksp_reserve_internal(ws, bytes, ZSTD_cwksp_alloc_buffers);
283
391
  }
284
392
 
285
393
  /**
286
- * Reserves and returns memory sized on and aligned on sizeof(unsigned).
394
+ * Reserves and returns memory sized on and aligned on ZSTD_CWKSP_ALIGNMENT_BYTES (64 bytes).
395
+ * This memory has been initialized at least once in the past.
396
+ * This doesn't mean it has been initialized this time, and it might contain data from previous
397
+ * operations.
398
+ * The main usage is for algorithms that might need read access into uninitialized memory.
399
+ * The algorithm must maintain safety under these conditions and must make sure it doesn't
400
+ * leak any of the past data (directly or in side channels).
287
401
  */
288
- MEM_STATIC void* ZSTD_cwksp_reserve_aligned(ZSTD_cwksp* ws, size_t bytes) {
289
- assert((bytes & (sizeof(U32)-1)) == 0);
290
- return ZSTD_cwksp_reserve_internal(ws, ZSTD_cwksp_align(bytes, sizeof(U32)), ZSTD_cwksp_alloc_aligned);
402
+ MEM_STATIC void* ZSTD_cwksp_reserve_aligned_init_once(ZSTD_cwksp* ws, size_t bytes)
403
+ {
404
+ size_t const alignedBytes = ZSTD_cwksp_align(bytes, ZSTD_CWKSP_ALIGNMENT_BYTES);
405
+ void* ptr = ZSTD_cwksp_reserve_internal(ws, alignedBytes, ZSTD_cwksp_alloc_aligned_init_once);
406
+ assert(((size_t)ptr & (ZSTD_CWKSP_ALIGNMENT_BYTES-1))== 0);
407
+ if(ptr && ptr < ws->initOnceStart) {
408
+ /* We assume the memory following the current allocation is either:
409
+ * 1. Not usable as initOnce memory (end of workspace)
410
+ * 2. Another initOnce buffer that has been allocated before (and so was previously memset)
411
+ * 3. An ASAN redzone, in which case we don't want to write on it
412
+ * For these reasons it should be fine to not explicitly zero every byte up to ws->initOnceStart.
413
+ * Note that we assume here that MSAN and ASAN cannot run in the same time. */
414
+ ZSTD_memset(ptr, 0, MIN((size_t)((U8*)ws->initOnceStart - (U8*)ptr), alignedBytes));
415
+ ws->initOnceStart = ptr;
416
+ }
417
+ #if ZSTD_MEMORY_SANITIZER
418
+ assert(__msan_test_shadow(ptr, bytes) == -1);
419
+ #endif
420
+ return ptr;
291
421
  }
292
422
 
293
423
  /**
294
- * Aligned on sizeof(unsigned). These buffers have the special property that
424
+ * Reserves and returns memory sized on and aligned on ZSTD_CWKSP_ALIGNMENT_BYTES (64 bytes).
425
+ */
426
+ MEM_STATIC void* ZSTD_cwksp_reserve_aligned(ZSTD_cwksp* ws, size_t bytes)
427
+ {
428
+ void* ptr = ZSTD_cwksp_reserve_internal(ws, ZSTD_cwksp_align(bytes, ZSTD_CWKSP_ALIGNMENT_BYTES),
429
+ ZSTD_cwksp_alloc_aligned);
430
+ assert(((size_t)ptr & (ZSTD_CWKSP_ALIGNMENT_BYTES-1))== 0);
431
+ return ptr;
432
+ }
433
+
434
+ /**
435
+ * Aligned on 64 bytes. These buffers have the special property that
295
436
  * their values remain constrained, allowing us to re-use them without
296
437
  * memset()-ing them.
297
438
  */
298
- MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes) {
299
- const ZSTD_cwksp_alloc_phase_e phase = ZSTD_cwksp_alloc_aligned;
300
- void* alloc = ws->tableEnd;
301
- void* end = (BYTE *)alloc + bytes;
302
- void* top = ws->allocStart;
439
+ MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes)
440
+ {
441
+ const ZSTD_cwksp_alloc_phase_e phase = ZSTD_cwksp_alloc_aligned_init_once;
442
+ void* alloc;
443
+ void* end;
444
+ void* top;
445
+
446
+ /* We can only start allocating tables after we are done reserving space for objects at the
447
+ * start of the workspace */
448
+ if(ws->phase < phase) {
449
+ if (ZSTD_isError(ZSTD_cwksp_internal_advance_phase(ws, phase))) {
450
+ return NULL;
451
+ }
452
+ }
453
+ alloc = ws->tableEnd;
454
+ end = (BYTE *)alloc + bytes;
455
+ top = ws->allocStart;
303
456
 
304
457
  DEBUGLOG(5, "cwksp: reserving %p table %zd bytes, %zd bytes remaining",
305
458
  alloc, bytes, ZSTD_cwksp_available_space(ws) - bytes);
306
459
  assert((bytes & (sizeof(U32)-1)) == 0);
307
- ZSTD_cwksp_internal_advance_phase(ws, phase);
308
460
  ZSTD_cwksp_assert_internal_consistency(ws);
309
461
  assert(end <= top);
310
462
  if (end > top) {
@@ -320,14 +472,18 @@ MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes) {
320
472
  }
321
473
  #endif
322
474
 
475
+ assert((bytes & (ZSTD_CWKSP_ALIGNMENT_BYTES-1)) == 0);
476
+ assert(((size_t)alloc & (ZSTD_CWKSP_ALIGNMENT_BYTES-1))== 0);
323
477
  return alloc;
324
478
  }
325
479
 
326
480
  /**
327
481
  * Aligned on sizeof(void*).
482
+ * Note : should happen only once, at workspace first initialization
328
483
  */
329
- MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) {
330
- size_t roundedBytes = ZSTD_cwksp_align(bytes, sizeof(void*));
484
+ MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes)
485
+ {
486
+ size_t const roundedBytes = ZSTD_cwksp_align(bytes, sizeof(void*));
331
487
  void* alloc = ws->objectEnd;
332
488
  void* end = (BYTE*)alloc + roundedBytes;
333
489
 
@@ -336,15 +492,15 @@ MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) {
336
492
  end = (BYTE *)end + 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE;
337
493
  #endif
338
494
 
339
- DEBUGLOG(5,
495
+ DEBUGLOG(4,
340
496
  "cwksp: reserving %p object %zd bytes (rounded to %zd), %zd bytes remaining",
341
497
  alloc, bytes, roundedBytes, ZSTD_cwksp_available_space(ws) - roundedBytes);
342
- assert(((size_t)alloc & (sizeof(void*)-1)) == 0);
343
- assert((bytes & (sizeof(void*)-1)) == 0);
498
+ assert((size_t)alloc % ZSTD_ALIGNOF(void*) == 0);
499
+ assert(bytes % ZSTD_ALIGNOF(void*) == 0);
344
500
  ZSTD_cwksp_assert_internal_consistency(ws);
345
501
  /* we must be in the first phase, no advance is possible */
346
502
  if (ws->phase != ZSTD_cwksp_alloc_objects || end > ws->workspaceEnd) {
347
- DEBUGLOG(4, "cwksp: object alloc failed!");
503
+ DEBUGLOG(3, "cwksp: object alloc failed!");
348
504
  ws->allocFailed = 1;
349
505
  return NULL;
350
506
  }
@@ -355,7 +511,7 @@ MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) {
355
511
  #if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
356
512
  /* Move alloc so there's ZSTD_CWKSP_ASAN_REDZONE_SIZE unused space on
357
513
  * either size. */
358
- alloc = (BYTE *)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE;
514
+ alloc = (BYTE*)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE;
359
515
  if (ws->isStatic == ZSTD_cwksp_dynamic_alloc) {
360
516
  __asan_unpoison_memory_region(alloc, bytes);
361
517
  }
@@ -364,17 +520,26 @@ MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) {
364
520
  return alloc;
365
521
  }
366
522
 
367
- MEM_STATIC void ZSTD_cwksp_mark_tables_dirty(ZSTD_cwksp* ws) {
523
+ MEM_STATIC void ZSTD_cwksp_mark_tables_dirty(ZSTD_cwksp* ws)
524
+ {
368
525
  DEBUGLOG(4, "cwksp: ZSTD_cwksp_mark_tables_dirty");
369
526
 
370
527
  #if ZSTD_MEMORY_SANITIZER && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE)
371
528
  /* To validate that the table re-use logic is sound, and that we don't
372
529
  * access table space that we haven't cleaned, we re-"poison" the table
373
- * space every time we mark it dirty. */
530
+ * space every time we mark it dirty.
531
+ * Since tableValidEnd space and initOnce space may overlap we don't poison
532
+ * the initOnce portion as it break its promise. This means that this poisoning
533
+ * check isn't always applied fully. */
374
534
  {
375
535
  size_t size = (BYTE*)ws->tableValidEnd - (BYTE*)ws->objectEnd;
376
536
  assert(__msan_test_shadow(ws->objectEnd, size) == -1);
377
- __msan_poison(ws->objectEnd, size);
537
+ if((BYTE*)ws->tableValidEnd < (BYTE*)ws->initOnceStart) {
538
+ __msan_poison(ws->objectEnd, size);
539
+ } else {
540
+ assert(ws->initOnceStart >= ws->objectEnd);
541
+ __msan_poison(ws->objectEnd, (BYTE*)ws->initOnceStart - (BYTE*)ws->objectEnd);
542
+ }
378
543
  }
379
544
  #endif
380
545
 
@@ -402,7 +567,7 @@ MEM_STATIC void ZSTD_cwksp_clean_tables(ZSTD_cwksp* ws) {
402
567
  assert(ws->tableValidEnd >= ws->objectEnd);
403
568
  assert(ws->tableValidEnd <= ws->allocStart);
404
569
  if (ws->tableValidEnd < ws->tableEnd) {
405
- ZSTD_memset(ws->tableValidEnd, 0, (BYTE*)ws->tableEnd - (BYTE*)ws->tableValidEnd);
570
+ ZSTD_memset(ws->tableValidEnd, 0, (size_t)((BYTE*)ws->tableEnd - (BYTE*)ws->tableValidEnd));
406
571
  }
407
572
  ZSTD_cwksp_mark_tables_clean(ws);
408
573
  }
@@ -439,11 +604,14 @@ MEM_STATIC void ZSTD_cwksp_clear(ZSTD_cwksp* ws) {
439
604
  #if ZSTD_MEMORY_SANITIZER && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE)
440
605
  /* To validate that the context re-use logic is sound, and that we don't
441
606
  * access stuff that this compression hasn't initialized, we re-"poison"
442
- * the workspace (or at least the non-static, non-table parts of it)
443
- * every time we start a new compression. */
607
+ * the workspace except for the areas in which we expect memory re-use
608
+ * without initialization (objects, valid tables area and init once
609
+ * memory). */
444
610
  {
445
- size_t size = (BYTE*)ws->workspaceEnd - (BYTE*)ws->tableValidEnd;
446
- __msan_poison(ws->tableValidEnd, size);
611
+ if((BYTE*)ws->tableValidEnd < (BYTE*)ws->initOnceStart) {
612
+ size_t size = (BYTE*)ws->initOnceStart - (BYTE*)ws->tableValidEnd;
613
+ __msan_poison(ws->tableValidEnd, size);
614
+ }
447
615
  }
448
616
  #endif
449
617
 
@@ -459,10 +627,10 @@ MEM_STATIC void ZSTD_cwksp_clear(ZSTD_cwksp* ws) {
459
627
  #endif
460
628
 
461
629
  ws->tableEnd = ws->objectEnd;
462
- ws->allocStart = ws->workspaceEnd;
630
+ ws->allocStart = ZSTD_cwksp_initialAllocStart(ws);
463
631
  ws->allocFailed = 0;
464
- if (ws->phase > ZSTD_cwksp_alloc_buffers) {
465
- ws->phase = ZSTD_cwksp_alloc_buffers;
632
+ if (ws->phase > ZSTD_cwksp_alloc_aligned_init_once) {
633
+ ws->phase = ZSTD_cwksp_alloc_aligned_init_once;
466
634
  }
467
635
  ZSTD_cwksp_assert_internal_consistency(ws);
468
636
  }
@@ -479,6 +647,7 @@ MEM_STATIC void ZSTD_cwksp_init(ZSTD_cwksp* ws, void* start, size_t size, ZSTD_c
479
647
  ws->workspaceEnd = (BYTE*)start + size;
480
648
  ws->objectEnd = ws->workspace;
481
649
  ws->tableValidEnd = ws->objectEnd;
650
+ ws->initOnceStart = ZSTD_cwksp_initialAllocStart(ws);
482
651
  ws->phase = ZSTD_cwksp_alloc_objects;
483
652
  ws->isStatic = isStatic;
484
653
  ZSTD_cwksp_clear(ws);
@@ -503,7 +672,7 @@ MEM_STATIC void ZSTD_cwksp_free(ZSTD_cwksp* ws, ZSTD_customMem customMem) {
503
672
 
504
673
  /**
505
674
  * 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 its used again).
675
+ * is left in an invalid state (src must be re-init()'ed before it's used again).
507
676
  */
508
677
  MEM_STATIC void ZSTD_cwksp_move(ZSTD_cwksp* dst, ZSTD_cwksp* src) {
509
678
  *dst = *src;
@@ -527,6 +696,18 @@ MEM_STATIC int ZSTD_cwksp_reserve_failed(const ZSTD_cwksp* ws) {
527
696
  * Functions Checking Free Space
528
697
  ***************************************/
529
698
 
699
+ /* ZSTD_alignmentSpaceWithinBounds() :
700
+ * Returns if the estimated space needed for a wksp is within an acceptable limit of the
701
+ * actual amount of space used.
702
+ */
703
+ MEM_STATIC int ZSTD_cwksp_estimated_space_within_bounds(const ZSTD_cwksp *const ws, size_t const estimatedSpace) {
704
+ /* We have an alignment space between objects and tables between tables and buffers, so we can have up to twice
705
+ * the alignment bytes difference between estimation and actual usage */
706
+ return (estimatedSpace - ZSTD_cwksp_slack_space_required()) <= ZSTD_cwksp_used(ws) &&
707
+ ZSTD_cwksp_used(ws) <= estimatedSpace;
708
+ }
709
+
710
+
530
711
  MEM_STATIC size_t ZSTD_cwksp_available_space(ZSTD_cwksp* ws) {
531
712
  return (size_t)((BYTE*)ws->allocStart - (BYTE*)ws->tableEnd);
532
713
  }