mini_racer 0.17.0.pre9 → 0.17.0.pre10

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b3be215eb4d4e72b01480ffa28863ea7ff1947b3f8cf0b6dcd860ffde2e48799
4
- data.tar.gz: adcae327e54c2c372871c255e4bfd19a07b28964cd4c7c51cbc1cc251d1f71db
3
+ metadata.gz: f09948c878aaefbc5e47285a3ee17db34e00de5d72e441cbb4ef45dd15e45f06
4
+ data.tar.gz: 95aa4a36b7612535524ff9ef6ca3116bde6dad9aa474c1c4b1af9427c0204969
5
5
  SHA512:
6
- metadata.gz: 98bdc234f17c0e16ae995c8fe3566f6ec80cbd92c569e4aa31ac1999d309ae2a197b0c7cb1c5de62f542f25b4f73287d0a34ab7967e1e24c32d02fc73ade33f2
7
- data.tar.gz: 7ade32c683f240c3e19eaa58b6a044192f57b1e651966c042654d401f1f5dae1aff20d1c545dd7fd05afb2b0f70659080825b5a788ab82379b119c497ac31e47
6
+ metadata.gz: 76a9a93bcb3bdfc0f7073e6a5501d8c96bd993bb85fe321ac54114154f015c0b0f1e2ba21067f79787831cff604f34e82079913b593dab559f4cb74e54781f17
7
+ data.tar.gz: ea1da1f7e66915a147fe614cff9a6de80e2d5a2953eabb0de422c0ad2839db940cc9dbf2c5c642604b03fbd5ab71a6c0fd26e15abb38d4f4652273243a41221f
data/CHANGELOG CHANGED
@@ -1,3 +1,6 @@
1
+ - 0.17.0.pr10 - 20-01-2025
2
+ - Added back support for partially deserialized objects (objects that do not translate across boundaries are returned as Error properties) - Ben Noordhuis
3
+
1
4
  - 0.17.0.pre9 - 13-01-2025
2
5
  - For backwards compatibility convert v8 return values to UTF-8 (invalidly encoded string still get returned using V8 encoding)
3
6
 
@@ -171,13 +171,14 @@ static void *rendezvous_callback(void *arg);
171
171
  typedef struct State
172
172
  {
173
173
  VALUE a, b;
174
+ uint8_t verbatim_keys:1;
174
175
  } State;
175
176
 
176
177
  // note: must be stack-allocated or VALUEs won't be visible to ruby's GC
177
178
  typedef struct DesCtx
178
179
  {
179
180
  State *tos;
180
- VALUE refs; // array
181
+ VALUE refs; // object refs array
181
182
  uint8_t transcode_latin1:1;
182
183
  char err[64];
183
184
  State stack[512];
@@ -199,7 +200,7 @@ static void DesCtx_init(DesCtx *c)
199
200
  {
200
201
  c->tos = c->stack;
201
202
  c->refs = rb_ary_new();
202
- *c->tos = (State){Qundef, Qundef};
203
+ *c->tos = (State){Qundef, Qundef, /*verbatim_keys*/0};
203
204
  *c->err = '\0';
204
205
  c->transcode_latin1 = 1; // convert to utf8
205
206
  }
@@ -220,7 +221,8 @@ static void put(DesCtx *c, VALUE v)
220
221
  if (*b == Qundef) {
221
222
  *b = v;
222
223
  } else {
223
- *b = rb_funcall(*b, rb_intern("to_s"), 0);
224
+ if (!c->tos->verbatim_keys)
225
+ *b = rb_funcall(*b, rb_intern("to_s"), 0);
224
226
  rb_hash_aset(*a, *b, v);
225
227
  *b = Qundef;
226
228
  }
@@ -242,7 +244,7 @@ static void push(DesCtx *c, VALUE v)
242
244
  snprintf(c->err, sizeof(c->err), "stack overflow");
243
245
  return;
244
246
  }
245
- *++c->tos = (State){v, Qundef};
247
+ *++c->tos = (State){v, Qundef, /*verbatim_keys*/0};
246
248
  rb_ary_push(c->refs, v);
247
249
  }
248
250
 
@@ -426,6 +428,20 @@ static void des_object_end(void *arg)
426
428
  pop(arg);
427
429
  }
428
430
 
431
+ static void des_map_begin(void *arg)
432
+ {
433
+ DesCtx *c;
434
+
435
+ c = arg;
436
+ push(c, rb_hash_new());
437
+ c->tos->verbatim_keys = 1; // don't stringify or intern keys
438
+ }
439
+
440
+ static void des_map_end(void *arg)
441
+ {
442
+ pop(arg);
443
+ }
444
+
429
445
  static void des_object_ref(void *arg, uint32_t id)
430
446
  {
431
447
  DesCtx *c;
@@ -11,6 +11,56 @@
11
11
  #include <cstring>
12
12
  #include <vector>
13
13
 
14
+ // note: the filter function gets called inside the safe context,
15
+ // i.e., the context that has not been tampered with by user JS
16
+ // convention: $-prefixed identifiers signify objects from the
17
+ // user JS context and should be handled with special care
18
+ static const char safe_context_script_source[] = R"js(
19
+ ;(function($globalThis) {
20
+ const {Map: $Map, Set: $Set} = $globalThis
21
+ const sentinel = {}
22
+ return function filter(v) {
23
+ if (typeof v === "function")
24
+ return sentinel
25
+ if (typeof v !== "object" || v === null)
26
+ return v
27
+ if (v instanceof $Map) {
28
+ const m = new Map()
29
+ for (let [k, t] of Map.prototype.entries.call(v)) {
30
+ t = filter(t)
31
+ if (t !== sentinel)
32
+ m.set(k, t)
33
+ }
34
+ return m
35
+ } else if (v instanceof $Set) {
36
+ const s = new Set()
37
+ for (let t of Set.prototype.values.call(v)) {
38
+ t = filter(t)
39
+ if (t !== sentinel)
40
+ s.add(t)
41
+ }
42
+ return s
43
+ } else {
44
+ const o = Array.isArray(v) ? [] : {}
45
+ const pds = Object.getOwnPropertyDescriptors(v)
46
+ for (const [k, d] of Object.entries(pds)) {
47
+ if (!d.enumerable)
48
+ continue
49
+ let t = d.value
50
+ if (d.get) {
51
+ // *not* d.get.call(...), may have been tampered with
52
+ t = Function.prototype.call.call(d.get, v, k)
53
+ }
54
+ t = filter(t)
55
+ if (t !== sentinel)
56
+ Object.defineProperty(o, k, {value: t, enumerable: true})
57
+ }
58
+ return o
59
+ }
60
+ }
61
+ })
62
+ )js";
63
+
14
64
  struct Callback
15
65
  {
16
66
  struct State *st;
@@ -32,8 +82,10 @@ struct State
32
82
  // extra context for when we need access to built-ins like Array
33
83
  // and want to be sure they haven't been tampered with by JS code
34
84
  v8::Local<v8::Context> safe_context;
35
- v8::Persistent<v8::Context> persistent_context; // single-thread mode only
36
- v8::Persistent<v8::Context> persistent_safe_context; // single-thread mode only
85
+ v8::Local<v8::Function> safe_context_function;
86
+ v8::Persistent<v8::Context> persistent_context; // single-thread mode only
87
+ v8::Persistent<v8::Context> persistent_safe_context; // single-thread mode only
88
+ v8::Persistent<v8::Function> persistent_safe_context_function; // single-thread mode only
37
89
  Context *ruby_context;
38
90
  int64_t max_memory;
39
91
  int err_reason;
@@ -73,6 +125,23 @@ struct Serialized
73
125
  // throws JS exception on serialization error
74
126
  bool reply(State& st, v8::Local<v8::Value> v)
75
127
  {
128
+ v8::TryCatch try_catch(st.isolate);
129
+ {
130
+ Serialized serialized(st, v);
131
+ if (serialized.data) {
132
+ v8_reply(st.ruby_context, serialized.data, serialized.size);
133
+ return true;
134
+ }
135
+ }
136
+ if (!try_catch.CanContinue()) {
137
+ try_catch.ReThrow();
138
+ return false;
139
+ }
140
+ auto recv = v8::Undefined(st.isolate);
141
+ if (!st.safe_context_function->Call(st.safe_context, recv, 1, &v).ToLocal(&v)) {
142
+ try_catch.ReThrow();
143
+ return false;
144
+ }
76
145
  Serialized serialized(st, v);
77
146
  if (serialized.data)
78
147
  v8_reply(st.ruby_context, serialized.data, serialized.size);
@@ -240,7 +309,29 @@ extern "C" State *v8_thread_init(Context *c, const uint8_t *snapshot_buf,
240
309
  st.safe_context = v8::Context::New(st.isolate);
241
310
  st.context = v8::Context::New(st.isolate);
242
311
  v8::Context::Scope context_scope(st.context);
312
+ {
313
+ v8::Context::Scope context_scope(st.safe_context);
314
+ auto source = v8::String::NewFromUtf8Literal(st.isolate, safe_context_script_source);
315
+ auto filename = v8::String::NewFromUtf8Literal(st.isolate, "safe_context_script.js");
316
+ v8::ScriptOrigin origin(filename);
317
+ auto script =
318
+ v8::Script::Compile(st.safe_context, source, &origin)
319
+ .ToLocalChecked();
320
+ auto function_v = script->Run(st.safe_context).ToLocalChecked();
321
+ auto function = v8::Function::Cast(*function_v);
322
+ auto recv = v8::Undefined(st.isolate);
323
+ v8::Local<v8::Value> arg = st.context->Global();
324
+ // grant the safe context access to the user context's globalThis
325
+ st.safe_context->SetSecurityToken(st.context->GetSecurityToken());
326
+ function_v =
327
+ function->Call(st.safe_context, recv, 1, &arg)
328
+ .ToLocalChecked();
329
+ // revoke access again now that the script did its one-time setup
330
+ st.safe_context->UseDefaultSecurityToken();
331
+ st.safe_context_function = v8::Local<v8::Function>::Cast(function_v);
332
+ }
243
333
  if (single_threaded) {
334
+ st.persistent_safe_context_function.Reset(st.isolate, st.safe_context_function);
244
335
  st.persistent_safe_context.Reset(st.isolate, st.safe_context);
245
336
  st.persistent_context.Reset(st.isolate, st.context);
246
337
  return pst; // intentionally returning early and keeping alive
@@ -792,12 +883,14 @@ extern "C" void v8_single_threaded_enter(State *pst, Context *c, void (*f)(Conte
792
883
  v8::Isolate::Scope isolate_scope(st.isolate);
793
884
  v8::HandleScope handle_scope(st.isolate);
794
885
  {
886
+ st.safe_context_function = v8::Local<v8::Function>::New(st.isolate, st.persistent_safe_context_function);
795
887
  st.safe_context = v8::Local<v8::Context>::New(st.isolate, st.persistent_safe_context);
796
888
  st.context = v8::Local<v8::Context>::New(st.isolate, st.persistent_context);
797
889
  v8::Context::Scope context_scope(st.context);
798
890
  f(c);
799
891
  st.context = v8::Local<v8::Context>();
800
892
  st.safe_context = v8::Local<v8::Context>();
893
+ st.safe_context_function = v8::Local<v8::Function>();
801
894
  }
802
895
  }
803
896
 
@@ -31,6 +31,8 @@ static void des_named_props_begin(void *arg);
31
31
  static void des_named_props_end(void *arg);
32
32
  static void des_object_begin(void *arg);
33
33
  static void des_object_end(void *arg);
34
+ static void des_map_begin(void *arg);
35
+ static void des_map_end(void *arg);
34
36
  static void des_object_ref(void *arg, uint32_t id);
35
37
  // des_error_begin: followed by des_object_begin + des_object_end calls
36
38
  static void des_error_begin(void *arg);
@@ -642,7 +644,7 @@ again:
642
644
  des_object_end(arg);
643
645
  break;
644
646
  case ';': // Map
645
- des_object_begin(arg);
647
+ des_map_begin(arg);
646
648
  for (u = 0; /*empty*/; u++) {
647
649
  if (*p >= pe)
648
650
  goto too_short;
@@ -658,7 +660,7 @@ again:
658
660
  goto bad_varint;
659
661
  if (t != 2*u)
660
662
  return bail(err, "map element count mismatch");
661
- des_object_end(arg);
663
+ des_map_end(arg);
662
664
  break;
663
665
  case '\'': // Set
664
666
  des_array_begin(arg);
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MiniRacer
4
- VERSION = "0.17.0.pre9"
4
+ VERSION = "0.17.0.pre10"
5
5
  LIBV8_NODE_VERSION = "~> 22.7.0.4"
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mini_racer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.17.0.pre9
4
+ version: 0.17.0.pre10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Saffron
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-01-13 00:00:00.000000000 Z
11
+ date: 2025-01-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -123,9 +123,9 @@ licenses:
123
123
  - MIT
124
124
  metadata:
125
125
  bug_tracker_uri: https://github.com/discourse/mini_racer/issues
126
- changelog_uri: https://github.com/discourse/mini_racer/blob/v0.17.0.pre9/CHANGELOG
127
- documentation_uri: https://www.rubydoc.info/gems/mini_racer/0.17.0.pre9
128
- source_code_uri: https://github.com/discourse/mini_racer/tree/v0.17.0.pre9
126
+ changelog_uri: https://github.com/discourse/mini_racer/blob/v0.17.0.pre10/CHANGELOG
127
+ documentation_uri: https://www.rubydoc.info/gems/mini_racer/0.17.0.pre10
128
+ source_code_uri: https://github.com/discourse/mini_racer/tree/v0.17.0.pre10
129
129
  post_install_message:
130
130
  rdoc_options: []
131
131
  require_paths: