extzstd 0.3.2 → 0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -3
  3. data/contrib/zstd/CHANGELOG +225 -1
  4. data/contrib/zstd/CONTRIBUTING.md +158 -75
  5. data/contrib/zstd/LICENSE +4 -4
  6. data/contrib/zstd/Makefile +106 -69
  7. data/contrib/zstd/Package.swift +36 -0
  8. data/contrib/zstd/README.md +64 -36
  9. data/contrib/zstd/SECURITY.md +15 -0
  10. data/contrib/zstd/TESTING.md +2 -3
  11. data/contrib/zstd/lib/BUCK +5 -7
  12. data/contrib/zstd/lib/Makefile +117 -199
  13. data/contrib/zstd/lib/README.md +37 -7
  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 +80 -86
  17. data/contrib/zstd/lib/common/compiler.h +225 -63
  18. data/contrib/zstd/lib/common/cpu.h +37 -1
  19. data/contrib/zstd/lib/common/debug.c +7 -1
  20. data/contrib/zstd/lib/common/debug.h +21 -12
  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 +93 -5
  24. data/contrib/zstd/lib/common/fse.h +12 -87
  25. data/contrib/zstd/lib/common/fse_decompress.c +37 -117
  26. data/contrib/zstd/lib/common/huf.h +97 -172
  27. data/contrib/zstd/lib/common/mem.h +58 -58
  28. data/contrib/zstd/lib/common/pool.c +38 -17
  29. data/contrib/zstd/lib/common/pool.h +10 -4
  30. data/contrib/zstd/lib/common/portability_macros.h +158 -0
  31. data/contrib/zstd/lib/common/threading.c +74 -14
  32. data/contrib/zstd/lib/common/threading.h +5 -10
  33. data/contrib/zstd/lib/common/xxhash.c +6 -814
  34. data/contrib/zstd/lib/common/xxhash.h +6930 -195
  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 +68 -154
  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 +75 -155
  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 +810 -259
  44. data/contrib/zstd/lib/compress/zstd_compress.c +2864 -919
  45. data/contrib/zstd/lib/compress/zstd_compress_internal.h +523 -192
  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 +251 -412
  51. data/contrib/zstd/lib/compress/zstd_compress_superblock.h +1 -1
  52. data/contrib/zstd/lib/compress/zstd_cwksp.h +284 -97
  53. data/contrib/zstd/lib/compress/zstd_double_fast.c +382 -133
  54. data/contrib/zstd/lib/compress/zstd_double_fast.h +14 -2
  55. data/contrib/zstd/lib/compress/zstd_fast.c +732 -260
  56. data/contrib/zstd/lib/compress/zstd_fast.h +3 -2
  57. data/contrib/zstd/lib/compress/zstd_lazy.c +1177 -390
  58. data/contrib/zstd/lib/compress/zstd_lazy.h +129 -14
  59. data/contrib/zstd/lib/compress/zstd_ldm.c +280 -210
  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 +516 -285
  63. data/contrib/zstd/lib/compress/zstd_opt.h +32 -8
  64. data/contrib/zstd/lib/compress/zstdmt_compress.c +202 -131
  65. data/contrib/zstd/lib/compress/zstdmt_compress.h +9 -6
  66. data/contrib/zstd/lib/decompress/huf_decompress.c +1149 -555
  67. data/contrib/zstd/lib/decompress/huf_decompress_amd64.S +595 -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 +583 -106
  71. data/contrib/zstd/lib/decompress/zstd_decompress_block.c +1054 -379
  72. data/contrib/zstd/lib/decompress/zstd_decompress_block.h +14 -3
  73. data/contrib/zstd/lib/decompress/zstd_decompress_internal.h +56 -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 +60 -44
  79. data/contrib/zstd/lib/dictBuilder/cover.h +6 -11
  80. data/contrib/zstd/lib/dictBuilder/divsufsort.c +1 -1
  81. data/contrib/zstd/lib/dictBuilder/fastcover.c +26 -18
  82. data/contrib/zstd/lib/dictBuilder/zdict.c +100 -101
  83. data/contrib/zstd/lib/legacy/zstd_legacy.h +38 -1
  84. data/contrib/zstd/lib/legacy/zstd_v01.c +18 -53
  85. data/contrib/zstd/lib/legacy/zstd_v01.h +1 -1
  86. data/contrib/zstd/lib/legacy/zstd_v02.c +28 -85
  87. data/contrib/zstd/lib/legacy/zstd_v02.h +1 -1
  88. data/contrib/zstd/lib/legacy/zstd_v03.c +29 -88
  89. data/contrib/zstd/lib/legacy/zstd_v03.h +1 -1
  90. data/contrib/zstd/lib/legacy/zstd_v04.c +27 -80
  91. data/contrib/zstd/lib/legacy/zstd_v04.h +1 -1
  92. data/contrib/zstd/lib/legacy/zstd_v05.c +36 -85
  93. data/contrib/zstd/lib/legacy/zstd_v05.h +1 -1
  94. data/contrib/zstd/lib/legacy/zstd_v06.c +44 -96
  95. data/contrib/zstd/lib/legacy/zstd_v06.h +1 -1
  96. data/contrib/zstd/lib/legacy/zstd_v07.c +37 -92
  97. data/contrib/zstd/lib/legacy/zstd_v07.h +1 -1
  98. data/contrib/zstd/lib/libzstd.mk +237 -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 +1030 -332
  103. data/contrib/zstd/lib/{common/zstd_errors.h → zstd_errors.h} +27 -8
  104. data/ext/extconf.rb +26 -7
  105. data/ext/extzstd.c +51 -24
  106. data/ext/extzstd.h +33 -6
  107. data/ext/extzstd_stream.c +74 -31
  108. data/ext/libzstd_conf.h +0 -1
  109. data/ext/zstd_decompress_asm.S +1 -0
  110. metadata +17 -7
  111. data/contrib/zstd/appveyor.yml +0 -292
  112. data/ext/depend +0 -2
@@ -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
@@ -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.
121
128
  *
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.
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. 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,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
- MEM_STATIC void ZSTD_cwksp_internal_advance_phase(
202
- ZSTD_cwksp* ws, ZSTD_cwksp_alloc_phase_e phase) {
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
- if (ws->phase < ZSTD_cwksp_alloc_buffers &&
206
- phase >= ZSTD_cwksp_alloc_buffers) {
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
- 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;
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
- return (ptr != NULL) && (ws->workspace <= ptr) && (ptr <= ws->workspaceEnd);
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* ZSTD_cwksp_reserve_internal(
238
- ZSTD_cwksp* ws, size_t bytes, ZSTD_cwksp_alloc_phase_e phase) {
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
- void* bottom = ws->tableEnd;
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
- alloc = (BYTE *)alloc - 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE;
365
+ bytes += 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE;
250
366
  #endif
251
367
 
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;
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
- alloc = (BYTE *)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE;
270
- if (ws->isStatic == ZSTD_cwksp_dynamic_alloc) {
271
- __asan_unpoison_memory_region(alloc, bytes);
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 sizeof(unsigned).
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* 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);
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
- * Aligned on sizeof(unsigned). These buffers have the special property that
295
- * their values remain constrained, allowing us to re-use them without
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
- 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;
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
- size_t roundedBytes = ZSTD_cwksp_align(bytes, sizeof(void*));
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(5,
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(((size_t)alloc & (sizeof(void*)-1)) == 0);
343
- assert((bytes & (sizeof(void*)-1)) == 0);
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(4, "cwksp: object alloc failed!");
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 *)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE;
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 re-use logic is sound, and that we don't
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
- __msan_poison(ws->objectEnd, size);
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 re-use logic is sound, and that we don't
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 (or at least the non-static, non-table parts of it)
443
- * every time we start a new compression. */
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
- size_t size = (BYTE*)ws->workspaceEnd - (BYTE*)ws->tableValidEnd;
446
- __msan_poison(ws->tableValidEnd, size);
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->workspaceEnd;
631
+ ws->allocStart = ZSTD_cwksp_initialAllocStart(ws);
463
632
  ws->allocFailed = 0;
464
- if (ws->phase > ZSTD_cwksp_alloc_buffers) {
465
- ws->phase = ZSTD_cwksp_alloc_buffers;
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 its used again).
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
  }