zstd-ruby 1.5.1.1 → 1.5.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/README.md +78 -5
  4. data/Rakefile +8 -2
  5. data/ext/zstdruby/common.h +15 -0
  6. data/ext/zstdruby/extconf.rb +1 -1
  7. data/ext/zstdruby/libzstd/common/allocations.h +55 -0
  8. data/ext/zstdruby/libzstd/common/bits.h +200 -0
  9. data/ext/zstdruby/libzstd/common/bitstream.h +19 -60
  10. data/ext/zstdruby/libzstd/common/compiler.h +26 -3
  11. data/ext/zstdruby/libzstd/common/cpu.h +1 -1
  12. data/ext/zstdruby/libzstd/common/debug.c +1 -1
  13. data/ext/zstdruby/libzstd/common/debug.h +1 -1
  14. data/ext/zstdruby/libzstd/common/entropy_common.c +12 -40
  15. data/ext/zstdruby/libzstd/common/error_private.c +9 -2
  16. data/ext/zstdruby/libzstd/common/error_private.h +1 -1
  17. data/ext/zstdruby/libzstd/common/fse.h +5 -83
  18. data/ext/zstdruby/libzstd/common/fse_decompress.c +7 -99
  19. data/ext/zstdruby/libzstd/common/huf.h +65 -156
  20. data/ext/zstdruby/libzstd/common/mem.h +39 -46
  21. data/ext/zstdruby/libzstd/common/pool.c +37 -16
  22. data/ext/zstdruby/libzstd/common/pool.h +9 -3
  23. data/ext/zstdruby/libzstd/common/portability_macros.h +28 -3
  24. data/ext/zstdruby/libzstd/common/threading.c +68 -14
  25. data/ext/zstdruby/libzstd/common/threading.h +5 -10
  26. data/ext/zstdruby/libzstd/common/xxhash.c +2 -2
  27. data/ext/zstdruby/libzstd/common/xxhash.h +8 -8
  28. data/ext/zstdruby/libzstd/common/zstd_common.c +1 -36
  29. data/ext/zstdruby/libzstd/common/zstd_deps.h +1 -1
  30. data/ext/zstdruby/libzstd/common/zstd_internal.h +20 -122
  31. data/ext/zstdruby/libzstd/common/zstd_trace.h +3 -3
  32. data/ext/zstdruby/libzstd/compress/clevels.h +1 -1
  33. data/ext/zstdruby/libzstd/compress/fse_compress.c +7 -124
  34. data/ext/zstdruby/libzstd/compress/hist.c +1 -1
  35. data/ext/zstdruby/libzstd/compress/hist.h +1 -1
  36. data/ext/zstdruby/libzstd/compress/huf_compress.c +234 -169
  37. data/ext/zstdruby/libzstd/compress/zstd_compress.c +1317 -594
  38. data/ext/zstdruby/libzstd/compress/zstd_compress_internal.h +272 -165
  39. data/ext/zstdruby/libzstd/compress/zstd_compress_literals.c +115 -39
  40. data/ext/zstdruby/libzstd/compress/zstd_compress_literals.h +16 -8
  41. data/ext/zstdruby/libzstd/compress/zstd_compress_sequences.c +13 -13
  42. data/ext/zstdruby/libzstd/compress/zstd_compress_sequences.h +1 -1
  43. data/ext/zstdruby/libzstd/compress/zstd_compress_superblock.c +25 -21
  44. data/ext/zstdruby/libzstd/compress/zstd_compress_superblock.h +1 -1
  45. data/ext/zstdruby/libzstd/compress/zstd_cwksp.h +162 -82
  46. data/ext/zstdruby/libzstd/compress/zstd_double_fast.c +95 -33
  47. data/ext/zstdruby/libzstd/compress/zstd_double_fast.h +3 -2
  48. data/ext/zstdruby/libzstd/compress/zstd_fast.c +434 -149
  49. data/ext/zstdruby/libzstd/compress/zstd_fast.h +3 -2
  50. data/ext/zstdruby/libzstd/compress/zstd_lazy.c +405 -348
  51. data/ext/zstdruby/libzstd/compress/zstd_lazy.h +4 -2
  52. data/ext/zstdruby/libzstd/compress/zstd_ldm.c +9 -7
  53. data/ext/zstdruby/libzstd/compress/zstd_ldm.h +1 -1
  54. data/ext/zstdruby/libzstd/compress/zstd_ldm_geartab.h +1 -1
  55. data/ext/zstdruby/libzstd/compress/zstd_opt.c +149 -100
  56. data/ext/zstdruby/libzstd/compress/zstd_opt.h +1 -1
  57. data/ext/zstdruby/libzstd/compress/zstdmt_compress.c +32 -16
  58. data/ext/zstdruby/libzstd/compress/zstdmt_compress.h +5 -2
  59. data/ext/zstdruby/libzstd/decompress/huf_decompress.c +434 -441
  60. data/ext/zstdruby/libzstd/decompress/huf_decompress_amd64.S +42 -37
  61. data/ext/zstdruby/libzstd/decompress/zstd_ddict.c +4 -4
  62. data/ext/zstdruby/libzstd/decompress/zstd_ddict.h +1 -1
  63. data/ext/zstdruby/libzstd/decompress/zstd_decompress.c +205 -80
  64. data/ext/zstdruby/libzstd/decompress/zstd_decompress_block.c +201 -81
  65. data/ext/zstdruby/libzstd/decompress/zstd_decompress_block.h +6 -1
  66. data/ext/zstdruby/libzstd/decompress/zstd_decompress_internal.h +4 -2
  67. data/ext/zstdruby/libzstd/dictBuilder/cover.c +19 -15
  68. data/ext/zstdruby/libzstd/dictBuilder/cover.h +1 -1
  69. data/ext/zstdruby/libzstd/dictBuilder/fastcover.c +2 -2
  70. data/ext/zstdruby/libzstd/dictBuilder/zdict.c +13 -91
  71. data/ext/zstdruby/libzstd/zdict.h +53 -31
  72. data/ext/zstdruby/libzstd/zstd.h +580 -135
  73. data/ext/zstdruby/libzstd/zstd_errors.h +27 -8
  74. data/ext/zstdruby/main.c +20 -0
  75. data/ext/zstdruby/skippable_frame.c +63 -0
  76. data/ext/zstdruby/streaming_compress.c +177 -0
  77. data/ext/zstdruby/streaming_compress.h +5 -0
  78. data/ext/zstdruby/streaming_decompress.c +123 -0
  79. data/ext/zstdruby/zstdruby.c +113 -31
  80. data/lib/zstd-ruby/version.rb +1 -1
  81. data/lib/zstd-ruby.rb +0 -1
  82. data/zstd-ruby.gemspec +1 -1
  83. metadata +11 -37
  84. data/.github/dependabot.yml +0 -8
  85. data/.github/workflows/ruby.yml +0 -35
  86. data/ext/zstdruby/libzstd/.gitignore +0 -3
  87. data/ext/zstdruby/libzstd/BUCK +0 -232
  88. data/ext/zstdruby/libzstd/Makefile +0 -357
  89. data/ext/zstdruby/libzstd/README.md +0 -217
  90. data/ext/zstdruby/libzstd/deprecated/zbuff.h +0 -214
  91. data/ext/zstdruby/libzstd/deprecated/zbuff_common.c +0 -26
  92. data/ext/zstdruby/libzstd/deprecated/zbuff_compress.c +0 -167
  93. data/ext/zstdruby/libzstd/deprecated/zbuff_decompress.c +0 -75
  94. data/ext/zstdruby/libzstd/dll/example/Makefile +0 -48
  95. data/ext/zstdruby/libzstd/dll/example/README.md +0 -63
  96. data/ext/zstdruby/libzstd/dll/example/build_package.bat +0 -20
  97. data/ext/zstdruby/libzstd/dll/example/fullbench-dll.sln +0 -25
  98. data/ext/zstdruby/libzstd/dll/example/fullbench-dll.vcxproj +0 -181
  99. data/ext/zstdruby/libzstd/legacy/zstd_legacy.h +0 -415
  100. data/ext/zstdruby/libzstd/legacy/zstd_v01.c +0 -2158
  101. data/ext/zstdruby/libzstd/legacy/zstd_v01.h +0 -94
  102. data/ext/zstdruby/libzstd/legacy/zstd_v02.c +0 -3518
  103. data/ext/zstdruby/libzstd/legacy/zstd_v02.h +0 -93
  104. data/ext/zstdruby/libzstd/legacy/zstd_v03.c +0 -3160
  105. data/ext/zstdruby/libzstd/legacy/zstd_v03.h +0 -93
  106. data/ext/zstdruby/libzstd/legacy/zstd_v04.c +0 -3647
  107. data/ext/zstdruby/libzstd/legacy/zstd_v04.h +0 -142
  108. data/ext/zstdruby/libzstd/legacy/zstd_v05.c +0 -4050
  109. data/ext/zstdruby/libzstd/legacy/zstd_v05.h +0 -162
  110. data/ext/zstdruby/libzstd/legacy/zstd_v06.c +0 -4154
  111. data/ext/zstdruby/libzstd/legacy/zstd_v06.h +0 -172
  112. data/ext/zstdruby/libzstd/legacy/zstd_v07.c +0 -4541
  113. data/ext/zstdruby/libzstd/legacy/zstd_v07.h +0 -187
  114. data/ext/zstdruby/libzstd/libzstd.mk +0 -185
  115. data/ext/zstdruby/libzstd/libzstd.pc.in +0 -16
  116. data/ext/zstdruby/libzstd/modulemap/module.modulemap +0 -4
  117. data/ext/zstdruby/zstdruby.h +0 -6
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 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" {
@@ -44,8 +46,9 @@ extern "C" {
44
46
  ***************************************/
45
47
  typedef enum {
46
48
  ZSTD_cwksp_alloc_objects,
47
- ZSTD_cwksp_alloc_buffers,
48
- ZSTD_cwksp_alloc_aligned
49
+ ZSTD_cwksp_alloc_aligned_init_once,
50
+ ZSTD_cwksp_alloc_aligned,
51
+ ZSTD_cwksp_alloc_buffers
49
52
  } ZSTD_cwksp_alloc_phase_e;
50
53
 
51
54
  /**
@@ -98,8 +101,8 @@ typedef enum {
98
101
  *
99
102
  * Workspace Layout:
100
103
  *
101
- * [ ... workspace ... ]
102
- * [objects][tables ... ->] free space [<- ... aligned][<- ... buffers]
104
+ * [ ... workspace ... ]
105
+ * [objects][tables ->] free space [<- buffers][<- aligned][<- init once]
103
106
  *
104
107
  * The various objects that live in the workspace are divided into the
105
108
  * following categories, and are allocated separately:
@@ -123,9 +126,18 @@ typedef enum {
123
126
  * uint32_t arrays, all of whose values are between 0 and (nextSrc - base).
124
127
  * Their sizes depend on the cparams. These tables are 64-byte aligned.
125
128
  *
126
- * - Aligned: these buffers are used for various purposes that require 4 byte
127
- * alignment, but don't require any initialization before they're used. These
128
- * buffers are each aligned to 64 bytes.
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.
129
141
  *
130
142
  * - Buffers: these buffers are used for various purposes that don't require
131
143
  * any alignment or initialization before they're used. This means they can
@@ -137,8 +149,9 @@ typedef enum {
137
149
  * correctly packed into the workspace buffer. That order is:
138
150
  *
139
151
  * 1. Objects
140
- * 2. Buffers
141
- * 3. Aligned/Tables
152
+ * 2. Init once / Tables
153
+ * 3. Aligned / Tables
154
+ * 4. Buffers / Tables
142
155
  *
143
156
  * Attempts to reserve objects of different types out of order will fail.
144
157
  */
@@ -150,6 +163,7 @@ typedef struct {
150
163
  void* tableEnd;
151
164
  void* tableValidEnd;
152
165
  void* allocStart;
166
+ void* initOnceStart;
153
167
 
154
168
  BYTE allocFailed;
155
169
  int workspaceOversizedDuration;
@@ -162,6 +176,7 @@ typedef struct {
162
176
  ***************************************/
163
177
 
164
178
  MEM_STATIC size_t ZSTD_cwksp_available_space(ZSTD_cwksp* ws);
179
+ MEM_STATIC void* ZSTD_cwksp_initialAllocStart(ZSTD_cwksp* ws);
165
180
 
166
181
  MEM_STATIC void ZSTD_cwksp_assert_internal_consistency(ZSTD_cwksp* ws) {
167
182
  (void)ws;
@@ -171,6 +186,20 @@ MEM_STATIC void ZSTD_cwksp_assert_internal_consistency(ZSTD_cwksp* ws) {
171
186
  assert(ws->tableEnd <= ws->allocStart);
172
187
  assert(ws->tableValidEnd <= ws->allocStart);
173
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
174
203
  }
175
204
 
176
205
  /**
@@ -217,14 +246,10 @@ MEM_STATIC size_t ZSTD_cwksp_aligned_alloc_size(size_t size) {
217
246
  * for internal purposes (currently only alignment).
218
247
  */
219
248
  MEM_STATIC size_t ZSTD_cwksp_slack_space_required(void) {
220
- /* For alignment, the wksp will always allocate an additional n_1=[1, 64] bytes
221
- * to align the beginning of tables section, as well as another n_2=[0, 63] bytes
222
- * to align the beginning of the aligned section.
223
- *
224
- * n_1 + n_2 == 64 bytes if the cwksp is freshly allocated, due to tables and
225
- * aligneds being sized in multiples of 64 bytes.
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;
226
251
  */
227
- size_t const slackSpace = ZSTD_CWKSP_ALIGNMENT_BYTES;
252
+ size_t const slackSpace = ZSTD_CWKSP_ALIGNMENT_BYTES * 2;
228
253
  return slackSpace;
229
254
  }
230
255
 
@@ -237,18 +262,28 @@ MEM_STATIC size_t ZSTD_cwksp_bytes_to_align_ptr(void* ptr, const size_t alignByt
237
262
  size_t const alignBytesMask = alignBytes - 1;
238
263
  size_t const bytes = (alignBytes - ((size_t)ptr & (alignBytesMask))) & alignBytesMask;
239
264
  assert((alignBytes & alignBytesMask) == 0);
240
- assert(bytes != ZSTD_CWKSP_ALIGNMENT_BYTES);
265
+ assert(bytes < alignBytes);
241
266
  return bytes;
242
267
  }
243
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
+
244
277
  /**
245
278
  * Internal function. Do not use directly.
246
- * Reserves the given number of bytes within the aligned/buffer segment of the wksp, which
247
- * counts from the end of the wksp. (as opposed to the object/table segment)
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).
248
281
  *
249
282
  * Returns a pointer to the beginning of that space.
250
283
  */
251
- MEM_STATIC void* ZSTD_cwksp_reserve_internal_buffer_space(ZSTD_cwksp* ws, size_t const bytes) {
284
+ MEM_STATIC void*
285
+ ZSTD_cwksp_reserve_internal_buffer_space(ZSTD_cwksp* ws, size_t const bytes)
286
+ {
252
287
  void* const alloc = (BYTE*)ws->allocStart - bytes;
253
288
  void* const bottom = ws->tableEnd;
254
289
  DEBUGLOG(5, "cwksp: reserving %p %zd bytes, %zd bytes remaining",
@@ -260,6 +295,8 @@ MEM_STATIC void* ZSTD_cwksp_reserve_internal_buffer_space(ZSTD_cwksp* ws, size_t
260
295
  ws->allocFailed = 1;
261
296
  return NULL;
262
297
  }
298
+ /* the area is reserved from the end of wksp.
299
+ * If it overlaps with tableValidEnd, it voids guarantees on values' range */
263
300
  if (alloc < ws->tableValidEnd) {
264
301
  ws->tableValidEnd = alloc;
265
302
  }
@@ -269,39 +306,32 @@ MEM_STATIC void* ZSTD_cwksp_reserve_internal_buffer_space(ZSTD_cwksp* ws, size_t
269
306
 
270
307
  /**
271
308
  * Moves the cwksp to the next phase, and does any necessary allocations.
309
+ * cwksp initialization must necessarily go through each phase in order.
272
310
  * Returns a 0 on success, or zstd error
273
311
  */
274
- MEM_STATIC size_t ZSTD_cwksp_internal_advance_phase(
275
- ZSTD_cwksp* ws, ZSTD_cwksp_alloc_phase_e phase) {
312
+ MEM_STATIC size_t
313
+ ZSTD_cwksp_internal_advance_phase(ZSTD_cwksp* ws, ZSTD_cwksp_alloc_phase_e phase)
314
+ {
276
315
  assert(phase >= ws->phase);
277
316
  if (phase > ws->phase) {
278
- /* Going from allocating objects to allocating buffers */
279
- if (ws->phase < ZSTD_cwksp_alloc_buffers &&
280
- 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) {
281
320
  ws->tableValidEnd = ws->objectEnd;
282
- }
321
+ ws->initOnceStart = ZSTD_cwksp_initialAllocStart(ws);
283
322
 
284
- /* Going from allocating buffers to allocating aligneds/tables */
285
- if (ws->phase < ZSTD_cwksp_alloc_aligned &&
286
- phase >= ZSTD_cwksp_alloc_aligned) {
287
- { /* Align the start of the "aligned" to 64 bytes. Use [1, 64] bytes. */
288
- size_t const bytesToAlign =
289
- ZSTD_CWKSP_ALIGNMENT_BYTES - ZSTD_cwksp_bytes_to_align_ptr(ws->allocStart, ZSTD_CWKSP_ALIGNMENT_BYTES);
290
- DEBUGLOG(5, "reserving aligned alignment addtl space: %zu", bytesToAlign);
291
- ZSTD_STATIC_ASSERT((ZSTD_CWKSP_ALIGNMENT_BYTES & (ZSTD_CWKSP_ALIGNMENT_BYTES - 1)) == 0); /* power of 2 */
292
- RETURN_ERROR_IF(!ZSTD_cwksp_reserve_internal_buffer_space(ws, bytesToAlign),
293
- memory_allocation, "aligned phase - alignment initial allocation failed!");
294
- }
295
323
  { /* Align the start of the tables to 64 bytes. Use [0, 63] bytes */
296
- void* const alloc = ws->objectEnd;
324
+ void *const alloc = ws->objectEnd;
297
325
  size_t const bytesToAlign = ZSTD_cwksp_bytes_to_align_ptr(alloc, ZSTD_CWKSP_ALIGNMENT_BYTES);
298
- void* const end = (BYTE*)alloc + bytesToAlign;
326
+ void *const objectEnd = (BYTE *) alloc + bytesToAlign;
299
327
  DEBUGLOG(5, "reserving table alignment addtl space: %zu", bytesToAlign);
300
- RETURN_ERROR_IF(end > ws->workspaceEnd, memory_allocation,
328
+ RETURN_ERROR_IF(objectEnd > ws->workspaceEnd, memory_allocation,
301
329
  "table phase - alignment initial allocation failed!");
302
- ws->objectEnd = end;
303
- ws->tableEnd = end;
304
- ws->tableValidEnd = end;
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
+ }
305
335
  }
306
336
  }
307
337
  ws->phase = phase;
@@ -313,15 +343,17 @@ MEM_STATIC size_t ZSTD_cwksp_internal_advance_phase(
313
343
  /**
314
344
  * Returns whether this object/buffer/etc was allocated in this workspace.
315
345
  */
316
- MEM_STATIC int ZSTD_cwksp_owns_buffer(const ZSTD_cwksp* ws, const void* ptr) {
317
- 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);
318
349
  }
319
350
 
320
351
  /**
321
352
  * Internal function. Do not use directly.
322
353
  */
323
- MEM_STATIC void* ZSTD_cwksp_reserve_internal(
324
- 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
+ {
325
357
  void* alloc;
326
358
  if (ZSTD_isError(ZSTD_cwksp_internal_advance_phase(ws, phase)) || bytes == 0) {
327
359
  return NULL;
@@ -340,7 +372,9 @@ MEM_STATIC void* ZSTD_cwksp_reserve_internal(
340
372
  if (alloc) {
341
373
  alloc = (BYTE *)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE;
342
374
  if (ws->isStatic == ZSTD_cwksp_dynamic_alloc) {
343
- __asan_unpoison_memory_region(alloc, bytes);
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);
344
378
  }
345
379
  }
346
380
  #endif
@@ -351,14 +385,46 @@ MEM_STATIC void* ZSTD_cwksp_reserve_internal(
351
385
  /**
352
386
  * Reserves and returns unaligned memory.
353
387
  */
354
- 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
+ {
355
390
  return (BYTE*)ZSTD_cwksp_reserve_internal(ws, bytes, ZSTD_cwksp_alloc_buffers);
356
391
  }
357
392
 
393
+ /**
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).
401
+ */
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;
421
+ }
422
+
358
423
  /**
359
424
  * Reserves and returns memory sized on and aligned on ZSTD_CWKSP_ALIGNMENT_BYTES (64 bytes).
360
425
  */
361
- MEM_STATIC void* ZSTD_cwksp_reserve_aligned(ZSTD_cwksp* ws, size_t bytes) {
426
+ MEM_STATIC void* ZSTD_cwksp_reserve_aligned(ZSTD_cwksp* ws, size_t bytes)
427
+ {
362
428
  void* ptr = ZSTD_cwksp_reserve_internal(ws, ZSTD_cwksp_align(bytes, ZSTD_CWKSP_ALIGNMENT_BYTES),
363
429
  ZSTD_cwksp_alloc_aligned);
364
430
  assert(((size_t)ptr & (ZSTD_CWKSP_ALIGNMENT_BYTES-1))== 0);
@@ -370,14 +436,19 @@ MEM_STATIC void* ZSTD_cwksp_reserve_aligned(ZSTD_cwksp* ws, size_t bytes) {
370
436
  * their values remain constrained, allowing us to re-use them without
371
437
  * memset()-ing them.
372
438
  */
373
- MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes) {
374
- const ZSTD_cwksp_alloc_phase_e phase = ZSTD_cwksp_alloc_aligned;
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;
375
442
  void* alloc;
376
443
  void* end;
377
444
  void* top;
378
445
 
379
- if (ZSTD_isError(ZSTD_cwksp_internal_advance_phase(ws, phase))) {
380
- return NULL;
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
+ }
381
452
  }
382
453
  alloc = ws->tableEnd;
383
454
  end = (BYTE *)alloc + bytes;
@@ -408,9 +479,11 @@ MEM_STATIC void* ZSTD_cwksp_reserve_table(ZSTD_cwksp* ws, size_t bytes) {
408
479
 
409
480
  /**
410
481
  * Aligned on sizeof(void*).
482
+ * Note : should happen only once, at workspace first initialization
411
483
  */
412
- MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) {
413
- 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*));
414
487
  void* alloc = ws->objectEnd;
415
488
  void* end = (BYTE*)alloc + roundedBytes;
416
489
 
@@ -419,7 +492,7 @@ MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) {
419
492
  end = (BYTE *)end + 2 * ZSTD_CWKSP_ASAN_REDZONE_SIZE;
420
493
  #endif
421
494
 
422
- DEBUGLOG(5,
495
+ DEBUGLOG(4,
423
496
  "cwksp: reserving %p object %zd bytes (rounded to %zd), %zd bytes remaining",
424
497
  alloc, bytes, roundedBytes, ZSTD_cwksp_available_space(ws) - roundedBytes);
425
498
  assert((size_t)alloc % ZSTD_ALIGNOF(void*) == 0);
@@ -427,7 +500,7 @@ MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) {
427
500
  ZSTD_cwksp_assert_internal_consistency(ws);
428
501
  /* we must be in the first phase, no advance is possible */
429
502
  if (ws->phase != ZSTD_cwksp_alloc_objects || end > ws->workspaceEnd) {
430
- DEBUGLOG(4, "cwksp: object alloc failed!");
503
+ DEBUGLOG(3, "cwksp: object alloc failed!");
431
504
  ws->allocFailed = 1;
432
505
  return NULL;
433
506
  }
@@ -438,7 +511,7 @@ MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) {
438
511
  #if ZSTD_ADDRESS_SANITIZER && !defined (ZSTD_ASAN_DONT_POISON_WORKSPACE)
439
512
  /* Move alloc so there's ZSTD_CWKSP_ASAN_REDZONE_SIZE unused space on
440
513
  * either size. */
441
- alloc = (BYTE *)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE;
514
+ alloc = (BYTE*)alloc + ZSTD_CWKSP_ASAN_REDZONE_SIZE;
442
515
  if (ws->isStatic == ZSTD_cwksp_dynamic_alloc) {
443
516
  __asan_unpoison_memory_region(alloc, bytes);
444
517
  }
@@ -447,17 +520,26 @@ MEM_STATIC void* ZSTD_cwksp_reserve_object(ZSTD_cwksp* ws, size_t bytes) {
447
520
  return alloc;
448
521
  }
449
522
 
450
- MEM_STATIC void ZSTD_cwksp_mark_tables_dirty(ZSTD_cwksp* ws) {
523
+ MEM_STATIC void ZSTD_cwksp_mark_tables_dirty(ZSTD_cwksp* ws)
524
+ {
451
525
  DEBUGLOG(4, "cwksp: ZSTD_cwksp_mark_tables_dirty");
452
526
 
453
527
  #if ZSTD_MEMORY_SANITIZER && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE)
454
528
  /* To validate that the table re-use logic is sound, and that we don't
455
529
  * access table space that we haven't cleaned, we re-"poison" the table
456
- * 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. */
457
534
  {
458
535
  size_t size = (BYTE*)ws->tableValidEnd - (BYTE*)ws->objectEnd;
459
536
  assert(__msan_test_shadow(ws->objectEnd, size) == -1);
460
- __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
+ }
461
543
  }
462
544
  #endif
463
545
 
@@ -485,7 +567,7 @@ MEM_STATIC void ZSTD_cwksp_clean_tables(ZSTD_cwksp* ws) {
485
567
  assert(ws->tableValidEnd >= ws->objectEnd);
486
568
  assert(ws->tableValidEnd <= ws->allocStart);
487
569
  if (ws->tableValidEnd < ws->tableEnd) {
488
- 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));
489
571
  }
490
572
  ZSTD_cwksp_mark_tables_clean(ws);
491
573
  }
@@ -522,11 +604,14 @@ MEM_STATIC void ZSTD_cwksp_clear(ZSTD_cwksp* ws) {
522
604
  #if ZSTD_MEMORY_SANITIZER && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE)
523
605
  /* To validate that the context re-use logic is sound, and that we don't
524
606
  * access stuff that this compression hasn't initialized, we re-"poison"
525
- * the workspace (or at least the non-static, non-table parts of it)
526
- * 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). */
527
610
  {
528
- size_t size = (BYTE*)ws->workspaceEnd - (BYTE*)ws->tableValidEnd;
529
- __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
+ }
530
615
  }
531
616
  #endif
532
617
 
@@ -542,10 +627,10 @@ MEM_STATIC void ZSTD_cwksp_clear(ZSTD_cwksp* ws) {
542
627
  #endif
543
628
 
544
629
  ws->tableEnd = ws->objectEnd;
545
- ws->allocStart = ws->workspaceEnd;
630
+ ws->allocStart = ZSTD_cwksp_initialAllocStart(ws);
546
631
  ws->allocFailed = 0;
547
- if (ws->phase > ZSTD_cwksp_alloc_buffers) {
548
- 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;
549
634
  }
550
635
  ZSTD_cwksp_assert_internal_consistency(ws);
551
636
  }
@@ -562,6 +647,7 @@ MEM_STATIC void ZSTD_cwksp_init(ZSTD_cwksp* ws, void* start, size_t size, ZSTD_c
562
647
  ws->workspaceEnd = (BYTE*)start + size;
563
648
  ws->objectEnd = ws->workspace;
564
649
  ws->tableValidEnd = ws->objectEnd;
650
+ ws->initOnceStart = ZSTD_cwksp_initialAllocStart(ws);
565
651
  ws->phase = ZSTD_cwksp_alloc_objects;
566
652
  ws->isStatic = isStatic;
567
653
  ZSTD_cwksp_clear(ws);
@@ -614,17 +700,11 @@ MEM_STATIC int ZSTD_cwksp_reserve_failed(const ZSTD_cwksp* ws) {
614
700
  * Returns if the estimated space needed for a wksp is within an acceptable limit of the
615
701
  * actual amount of space used.
616
702
  */
617
- MEM_STATIC int ZSTD_cwksp_estimated_space_within_bounds(const ZSTD_cwksp* const ws,
618
- size_t const estimatedSpace, int resizedWorkspace) {
619
- if (resizedWorkspace) {
620
- /* Resized/newly allocated wksp should have exact bounds */
621
- return ZSTD_cwksp_used(ws) == estimatedSpace;
622
- } else {
623
- /* Due to alignment, when reusing a workspace, we can actually consume 63 fewer or more bytes
624
- * than estimatedSpace. See the comments in zstd_cwksp.h for details.
625
- */
626
- return (ZSTD_cwksp_used(ws) >= estimatedSpace - 63) && (ZSTD_cwksp_used(ws) <= estimatedSpace + 63);
627
- }
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;
628
708
  }
629
709
 
630
710