zstd-ruby 2.0.8 → 2.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2747a2ccb21d362d5523b5c986fd5f45e7bc2007a40710c303e14e69b66dd626
4
- data.tar.gz: 9b396596f0877e8da07fedf4a90e5d54af41414262dd12754faff6b71e56b771
3
+ metadata.gz: fb07a33ae127aa325dd6ccb9aba7af6456689ff2eb41aa5e9a830b63d15df6b2
4
+ data.tar.gz: 4925a30a7b202f632b199d0ac43f448de4e0ac841c23be2927e863e50171ef08
5
5
  SHA512:
6
- metadata.gz: 5cdeca9f57890066be8ad60fa7768b0920faac9bae169f6ca5069302a38e48a8c1e22d6b93a13abda415447dc7d750f38aef923527d055d04075d0d81d9a6556
7
- data.tar.gz: a625f95323296768a68ccbc98fa4a24175d8a6d2643b3ef7ee4bf3b7cb1ceef2afc4ba4ba263b7bf2b7dbbc279ae89231f92d0d043aa4a1c6d96e8b8e03aa776
6
+ metadata.gz: 0b507405b5fbe9a418553d90842f1eecacc6f73ba8a82a212d520732087153683c64bced408324754816342329b9a8bead006cdd8c5e564bd184bd64e5d47212
7
+ data.tar.gz: d6cb8bc02eb3e1b4d3f1a32c889f245d29ad2f84d786669934d08b498b146b37fe335e7c646fbb2d8da82142396c9bb20542695b4bbef41c0565fb9348e6cefc
data/.gitignore CHANGED
@@ -22,3 +22,4 @@ vendor/
22
22
  .ruby-version
23
23
 
24
24
  .vscode
25
+ mise.toml
@@ -24,7 +24,11 @@ static int convert_compression_level(ZSTD_CCtx* ctx, VALUE compression_level_val
24
24
  return NUM2INT(compression_level_value);
25
25
  }
26
26
 
27
- static void set_compress_params(ZSTD_CCtx* const ctx, VALUE kwargs)
27
+ /* Returns the Zstd::CDict given as `dict:`, or Qnil. ZSTD_CCtx_refCDict only
28
+ borrows the pointer, so a caller that keeps the ZSTD_CCtx alive beyond this
29
+ call has to keep the returned object reachable for just as long. A String
30
+ dictionary needs no such handling: ZSTD_CCtx_loadDictionary copies it. */
31
+ static VALUE set_compress_params(ZSTD_CCtx* const ctx, VALUE kwargs)
28
32
  {
29
33
  ID kwargs_keys[2];
30
34
  kwargs_keys[0] = rb_intern("level");
@@ -46,6 +50,7 @@ static void set_compress_params(ZSTD_CCtx* const ctx, VALUE kwargs)
46
50
  ZSTD_freeCCtx(ctx);
47
51
  rb_raise(rb_eRuntimeError, "%s", "ZSTD_CCtx_refCDict failed");
48
52
  }
53
+ return kwargs_values[1];
49
54
  } else if (TYPE(kwargs_values[1]) == T_STRING) {
50
55
  char* dict_buffer = RSTRING_PTR(kwargs_values[1]);
51
56
  size_t dict_size = RSTRING_LEN(kwargs_values[1]);
@@ -59,6 +64,7 @@ static void set_compress_params(ZSTD_CCtx* const ctx, VALUE kwargs)
59
64
  rb_raise(rb_eArgError, "`dict:` must be a Zstd::CDict or a String");
60
65
  }
61
66
  }
67
+ return Qnil;
62
68
  }
63
69
 
64
70
  struct stream_compress_params {
@@ -122,7 +128,9 @@ static size_t zstd_compress(ZSTD_CCtx* const ctx, char* output_data, size_t outp
122
128
  #endif
123
129
  }
124
130
 
125
- static void set_decompress_params(ZSTD_DCtx* const dctx, VALUE kwargs)
131
+ /* Returns the Zstd::DDict given as `dict:`, or Qnil. See set_compress_params:
132
+ ZSTD_DCtx_refDDict borrows, ZSTD_DCtx_loadDictionary copies. */
133
+ static VALUE set_decompress_params(ZSTD_DCtx* const dctx, VALUE kwargs)
126
134
  {
127
135
  ID kwargs_keys[1];
128
136
  kwargs_keys[0] = rb_intern("dict");
@@ -137,6 +145,7 @@ static void set_decompress_params(ZSTD_DCtx* const dctx, VALUE kwargs)
137
145
  ZSTD_freeDCtx(dctx);
138
146
  rb_raise(rb_eRuntimeError, "%s", "ZSTD_DCtx_refDDict failed");
139
147
  }
148
+ return kwargs_values[0];
140
149
  } else if (TYPE(kwargs_values[0]) == T_STRING) {
141
150
  char* dict_buffer = RSTRING_PTR(kwargs_values[0]);
142
151
  size_t dict_size = RSTRING_LEN(kwargs_values[0]);
@@ -150,6 +159,7 @@ static void set_decompress_params(ZSTD_DCtx* const dctx, VALUE kwargs)
150
159
  rb_raise(rb_eArgError, "`dict:` must be a Zstd::DDict or a String");
151
160
  }
152
161
  }
162
+ return Qnil;
153
163
  }
154
164
 
155
165
  struct stream_decompress_params {
@@ -26,7 +26,7 @@ def ext_export_filename
26
26
  name
27
27
  end
28
28
 
29
- $CFLAGS = '-I. -O3 -std=c99 -DZSTD_STATIC_LINKING_ONLY -DZSTD_MULTITHREAD -pthread -DDEBUGLEVEL=0 -fvisibility=hidden -DZSTDLIB_VISIBLE=\'__attribute__((visibility("hidden")))\' -DZSTDLIB_HIDDEN=\'__attribute__((visibility("hidden")))\''
29
+ $CFLAGS += ' -I. -O3 -std=c99 -DZSTD_STATIC_LINKING_ONLY -DZSTD_MULTITHREAD -pthread -DDEBUGLEVEL=0 -fvisibility=hidden -DZSTDLIB_VISIBLE=\'__attribute__((visibility("hidden")))\' -DZSTDLIB_HIDDEN=\'__attribute__((visibility("hidden")))\''
30
30
  $CPPFLAGS += " -fdeclspec" if CONFIG['CXX'] =~ /clang/
31
31
 
32
32
  # macOS specific: Use exported_symbols_list to control symbol visibility
@@ -5,6 +5,7 @@ struct streaming_compress_t {
5
5
  VALUE buf;
6
6
  size_t buf_size;
7
7
  VALUE pending; /* accumulate compressed bytes produced by write() */
8
+ VALUE dict; /* Zstd::CDict the ctx borrows a pointer into, or Qnil */
8
9
  };
9
10
 
10
11
  static void
@@ -14,9 +15,11 @@ streaming_compress_mark(void *p)
14
15
  #ifdef HAVE_RB_GC_MARK_MOVABLE
15
16
  rb_gc_mark_movable(sc->buf);
16
17
  rb_gc_mark_movable(sc->pending);
18
+ rb_gc_mark_movable(sc->dict);
17
19
  #else
18
20
  rb_gc_mark(sc->buf);
19
21
  rb_gc_mark(sc->pending);
22
+ rb_gc_mark(sc->dict);
20
23
  #endif
21
24
  }
22
25
 
@@ -44,6 +47,7 @@ streaming_compress_compact(void *p)
44
47
  struct streaming_compress_t *sc = p;
45
48
  sc->buf = rb_gc_location(sc->buf);
46
49
  sc->pending = rb_gc_location(sc->pending);
50
+ sc->dict = rb_gc_location(sc->dict);
47
51
  }
48
52
  #endif
49
53
 
@@ -69,6 +73,7 @@ rb_streaming_compress_allocate(VALUE klass)
69
73
  RB_OBJ_WRITE(obj, &sc->buf, Qnil);
70
74
  sc->buf_size = 0;
71
75
  RB_OBJ_WRITE(obj, &sc->pending, Qnil);
76
+ RB_OBJ_WRITE(obj, &sc->dict, Qnil);
72
77
  return obj;
73
78
  }
74
79
 
@@ -86,9 +91,10 @@ rb_streaming_compress_initialize(int argc, VALUE *argv, VALUE obj)
86
91
  if (ctx == NULL) {
87
92
  rb_raise(rb_eRuntimeError, "%s", "ZSTD_createCCtx error");
88
93
  }
89
- set_compress_params(ctx, kwargs);
94
+ VALUE dict = set_compress_params(ctx, kwargs);
90
95
 
91
96
  sc->ctx = ctx;
97
+ RB_OBJ_WRITE(obj, &sc->dict, dict);
92
98
  RB_OBJ_WRITE(obj, &sc->buf, rb_str_new(NULL, buffOutSize));
93
99
  sc->buf_size = buffOutSize;
94
100
  RB_OBJ_WRITE(obj, &sc->pending, rb_str_new(0, 0));
@@ -4,6 +4,7 @@ struct streaming_decompress_t {
4
4
  ZSTD_DCtx* dctx;
5
5
  VALUE buf;
6
6
  size_t buf_size;
7
+ VALUE dict; /* Zstd::DDict the dctx borrows a pointer into, or Qnil */
7
8
  };
8
9
 
9
10
  static void
@@ -12,8 +13,10 @@ streaming_decompress_mark(void *p)
12
13
  struct streaming_decompress_t *sd = p;
13
14
  #ifdef HAVE_RB_GC_MARK_MOVABLE
14
15
  rb_gc_mark_movable(sd->buf);
16
+ rb_gc_mark_movable(sd->dict);
15
17
  #else
16
18
  rb_gc_mark(sd->buf);
19
+ rb_gc_mark(sd->dict);
17
20
  #endif
18
21
  }
19
22
 
@@ -40,6 +43,7 @@ streaming_decompress_compact(void *p)
40
43
  {
41
44
  struct streaming_decompress_t *sd = p;
42
45
  sd->buf = rb_gc_location(sd->buf);
46
+ sd->dict = rb_gc_location(sd->dict);
43
47
  }
44
48
  #endif
45
49
 
@@ -64,6 +68,7 @@ rb_streaming_decompress_allocate(VALUE klass)
64
68
  sd->dctx = NULL;
65
69
  RB_OBJ_WRITE(obj, &sd->buf, Qnil);
66
70
  sd->buf_size = 0;
71
+ RB_OBJ_WRITE(obj, &sd->dict, Qnil);
67
72
  return obj;
68
73
  }
69
74
 
@@ -81,9 +86,10 @@ rb_streaming_decompress_initialize(int argc, VALUE *argv, VALUE obj)
81
86
  if (dctx == NULL) {
82
87
  rb_raise(rb_eRuntimeError, "%s", "ZSTD_createDCtx error");
83
88
  }
84
- set_decompress_params(dctx, kwargs);
89
+ VALUE dict = set_decompress_params(dctx, kwargs);
85
90
 
86
91
  sd->dctx = dctx;
92
+ RB_OBJ_WRITE(obj, &sd->dict, dict);
87
93
  RB_OBJ_WRITE(obj, &sd->buf, rb_str_new(NULL, buffOutSize));
88
94
  sd->buf_size = buffOutSize;
89
95
 
@@ -51,6 +51,7 @@ static VALUE decode_one_frame(ZSTD_DCtx* dctx, const unsigned char* src, size_t
51
51
 
52
52
  for (;;) {
53
53
  ZSTD_outBuffer o = (ZSTD_outBuffer){ buf, cap, 0 };
54
+ size_t const in_pos_before = in.pos;
54
55
  size_t ret = ZSTD_decompressStream(dctx, &o, &in);
55
56
  if (ZSTD_isError(ret)) {
56
57
  xfree(buf);
@@ -62,6 +63,13 @@ static VALUE decode_one_frame(ZSTD_DCtx* dctx, const unsigned char* src, size_t
62
63
  if (ret == 0) {
63
64
  break;
64
65
  }
66
+ /* A non-zero return is a "need more input" hint, not an error, and libzstd's
67
+ own noForwardProgress guard is bypassed by the early return it takes on a
68
+ truncated frame header -- so the stall has to be detected here. */
69
+ if (o.pos == 0 && in.pos == in_pos_before) {
70
+ xfree(buf);
71
+ rb_raise(rb_eRuntimeError, "ZSTD_decompressStream failed: truncated or incomplete frame");
72
+ }
65
73
  }
66
74
  xfree(buf);
67
75
  if (consumed) {
@@ -1,3 +1,3 @@
1
1
  module Zstd
2
- VERSION = "2.0.8"
2
+ VERSION = "2.0.9"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zstd-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.8
4
+ version: 2.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - SpringMT
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-08-09 00:00:00.000000000 Z
11
+ date: 2026-09-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler