psych 5.4.0-java → 5.5.0-java

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: e62755a6f6b0b7f7eebe2651fbb2b1c81538e2bcbc1d010fe58574b7ede21b84
4
- data.tar.gz: 39bc8e482405345038582fb548d6164bdcea116424786c508be42f25753567e8
3
+ metadata.gz: 7429988183a896844c649cc6c90e91f722a0a5bb97d48266e76f3ec81706a750
4
+ data.tar.gz: 27660902dac288a8ff13063046809f41c22dc4371e0fe4d496b34ad63f7ffa37
5
5
  SHA512:
6
- metadata.gz: d2fcda255f004e0fa53379d5192acf1e77b0cb5f8af431495acda6291fd818a2089569d4e840aca9920ad3a70d92d2eb4af2fe4e98e957410a08f4c3b94ab990
7
- data.tar.gz: dc0f517aa6da6eaf7fe614229069d01c34edc3b29da6056e613a66f7cd33034599e1b3d761d4c1ea879d1c1e8ad92df5f5489ef7b242f6fff56723d6b6cc3259
6
+ metadata.gz: 675ef39857c198e61ca4e3aa2b8b3db97971e09ce3330a3d5fab1d4658d0c73eef19e001616064fbd8783414dd8807ddec60a0aebc557c770b93bf54f6eff3aa
7
+ data.tar.gz: bd40e9dd4011b980631e11615f60ade26630ef7e9b1a4ef64fe982e52f0d90dc610a83c0610a02c734741ec3d0d13b18978e92bb45f7f7693da0a5c389327cef
data/README.md CHANGED
@@ -23,6 +23,7 @@ Psych.dump("foo") # => "--- foo\n...\n"
23
23
  ## Dependencies
24
24
 
25
25
  * libyaml
26
+ * libfyaml (optional, only for the experimental `--enable-libfyaml` backend)
26
27
 
27
28
  ## Installation
28
29
 
@@ -57,6 +58,58 @@ gem 'psych'
57
58
 
58
59
  JRuby ships with a pure Java implementation of Psych.
59
60
 
61
+ ## Experimental libfyaml backend
62
+
63
+ Psych ships an experimental, opt-in backend built on
64
+ [libfyaml](https://github.com/pantoniou/libfyaml), a fully YAML 1.2 compliant
65
+ parser and emitter. It is compiled only when you explicitly pass
66
+ `--enable-libfyaml` at build time. Without the flag the default libyaml
67
+ backend is used and nothing changes.
68
+
69
+ ```bash
70
+ # libfyaml and pkg-config must be installed first, for example:
71
+ # apt-get install libfyaml-dev # Debian/Ubuntu
72
+ # brew install libfyaml # macOS
73
+ gem install psych -- --enable-libfyaml
74
+ ```
75
+
76
+ This backend is not supported on Windows.
77
+
78
+ Because libfyaml follows YAML 1.2, the YAML 1.1 booleans `yes`, `no`, `on`, and
79
+ `off` load as plain strings instead of `true`/`false` (only `true`/`false` are
80
+ booleans). This resolves the so-called "Norway problem", where the country
81
+ code `no` was parsed as `false`:
82
+
83
+ ```ruby
84
+ Psych.load("country: no") # => {"country" => "no"}
85
+ ```
86
+
87
+ You can check which backend is active:
88
+
89
+ ```ruby
90
+ Psych::BACKEND # => "libfyaml" (or "libyaml")
91
+ Psych.libfyaml_version # => "0.9.6"
92
+ ```
93
+
94
+ The backend is experimental. Its output is valid YAML but is formatted
95
+ differently from libyaml in places, and a few emitter edge cases are not yet
96
+ matched. The default libyaml backend remains the supported choice.
97
+
98
+ Two more differences are worth knowing. Scalars emitted with the default
99
+ (`ANY`) style may be quoted or laid out differently from libyaml, so
100
+ byte-for-byte output is not guaranteed to match. On a parse error,
101
+ `Psych::SyntaxError#problem` carries libfyaml's full diagnostic message and
102
+ `Psych::SyntaxError#context` is always `nil`, whereas libyaml splits the
103
+ description across `#problem` and `#context`.
104
+
105
+ This backend targets YAML 1.2 compliance, not speed. In a rough
106
+ single-machine benchmark that loads and dumps in-memory documents, parsing
107
+ was roughly on par with libyaml (sometimes faster on string-heavy input),
108
+ while emitting was about 1.7x to 1.9x slower. Your numbers will vary, but the
109
+ shape holds: libfyaml is competitive at parsing and slower at emitting. Use
110
+ this backend when you need YAML 1.2 semantics. If throughput is your priority,
111
+ keep using the default libyaml backend.
112
+
60
113
  ## Release
61
114
 
62
115
  We used the trusted publisher and [rubygems/release-gem](https://github.com/rubygems/release-gem) workflow.
data/ext/psych/extconf.rb CHANGED
@@ -2,6 +2,28 @@
2
2
  # frozen_string_literal: true
3
3
  require 'mkmf'
4
4
 
5
+ # Experimental, opt-in libfyaml backend. Only used when psych is built with
6
+ # --enable-libfyaml. Without the flag nothing below changes and the default
7
+ # libyaml backend is built exactly as before.
8
+ if enable_config("libfyaml", false)
9
+ if $mswin or $mingw or $cygwin
10
+ abort "The libfyaml backend (--enable-libfyaml) is not supported on Windows"
11
+ end
12
+ unless pkg_config('libfyaml')
13
+ abort "libfyaml was requested with --enable-libfyaml but was not found via pkg-config"
14
+ end
15
+ # libfyaml 0.8 and earlier crash psych's emitter, so require a known-good
16
+ # version rather than building something that segfaults at runtime.
17
+ pkgconfig = ENV["PKG_CONFIG"] || "pkg-config"
18
+ unless system(pkgconfig, "--atleast-version=0.9", "libfyaml")
19
+ abort "The libfyaml backend requires libfyaml 0.9 or newer"
20
+ end
21
+ $defs << "-DPSYCH_USE_LIBFYAML"
22
+
23
+ create_makefile 'psych'
24
+ return
25
+ end
26
+
5
27
  if $mswin or $mingw or $cygwin
6
28
  $CPPFLAGS << " -DYAML_DECLARE_STATIC"
7
29
  end
data/ext/psych/psych.c CHANGED
@@ -2,14 +2,25 @@
2
2
 
3
3
  /* call-seq: Psych.libyaml_version
4
4
  *
5
- * Returns the version of libyaml being used
5
+ * Returns the version of the underlying YAML library as a three-element
6
+ * array. This is libyaml by default. On the experimental libfyaml backend,
7
+ * where libyaml is not linked, it reports the libfyaml version instead.
6
8
  */
7
9
  static VALUE libyaml_version(VALUE module)
8
10
  {
9
11
  int major, minor, patch;
10
12
  VALUE list[3];
11
13
 
14
+ #ifdef PSYCH_USE_LIBFYAML
15
+ /* Experimental libfyaml backend: there is no libyaml linked in. Report
16
+ * the libfyaml version so callers still receive a 3-element version. */
17
+ const struct fy_version *v = fy_version_default();
18
+ major = v ? v->major : 0;
19
+ minor = v ? v->minor : 0;
20
+ patch = 0;
21
+ #else
12
22
  yaml_get_version(&major, &minor, &patch);
23
+ #endif
13
24
 
14
25
  list[0] = INT2NUM(major);
15
26
  list[1] = INT2NUM(minor);
@@ -18,6 +29,20 @@ static VALUE libyaml_version(VALUE module)
18
29
  return rb_ary_new4((long)3, list);
19
30
  }
20
31
 
32
+ #ifdef PSYCH_USE_LIBFYAML
33
+ /* call-seq: Psych.libfyaml_version
34
+ *
35
+ * Returns the libfyaml version string. This method is only defined when
36
+ * psych was built with the experimental libfyaml backend
37
+ * (+--enable-libfyaml+).
38
+ */
39
+ static VALUE libfyaml_version(VALUE module)
40
+ {
41
+ const char *v = fy_library_version();
42
+ return v ? rb_usascii_str_new2(v) : Qnil;
43
+ }
44
+ #endif
45
+
21
46
  VALUE mPsych;
22
47
 
23
48
  void Init_psych(void)
@@ -29,6 +54,13 @@ void Init_psych(void)
29
54
 
30
55
  rb_define_singleton_method(mPsych, "libyaml_version", libyaml_version, 0);
31
56
 
57
+ #ifdef PSYCH_USE_LIBFYAML
58
+ rb_define_singleton_method(mPsych, "libfyaml_version", libfyaml_version, 0);
59
+ rb_define_const(mPsych, "BACKEND", rb_usascii_str_new2("libfyaml"));
60
+ #else
61
+ rb_define_const(mPsych, "BACKEND", rb_usascii_str_new2("libyaml"));
62
+ #endif
63
+
32
64
  Init_psych_parser();
33
65
  Init_psych_emitter();
34
66
  Init_psych_to_ruby();
data/ext/psych/psych.h CHANGED
@@ -4,7 +4,11 @@
4
4
  #include <ruby.h>
5
5
  #include <ruby/encoding.h>
6
6
 
7
+ #ifdef PSYCH_USE_LIBFYAML
8
+ #include <libfyaml.h>
9
+ #else
7
10
  #include <yaml.h>
11
+ #endif
8
12
 
9
13
  #include <psych_parser.h>
10
14
  #include <psych_emitter.h>
@@ -1,5 +1,7 @@
1
1
  #include <psych.h>
2
2
 
3
+ #ifndef PSYCH_USE_LIBFYAML
4
+
3
5
  #if !defined(RARRAY_CONST_PTR)
4
6
  #define RARRAY_CONST_PTR(s) (const VALUE *)RARRAY_PTR(s)
5
7
  #endif
@@ -587,3 +589,5 @@ void Init_psych_emitter(void)
587
589
  id_indentation = rb_intern("indentation");
588
590
  id_canonical = rb_intern("canonical");
589
591
  }
592
+
593
+ #endif /* PSYCH_USE_LIBFYAML */
@@ -1,9 +1,10 @@
1
1
  #include <psych.h>
2
2
 
3
+ #ifndef PSYCH_USE_LIBFYAML
4
+
3
5
  VALUE cPsychParser;
4
6
 
5
7
  static ID id_read;
6
- static ID id_path;
7
8
  static ID id_empty;
8
9
  static ID id_start_stream;
9
10
  static ID id_end_stream;
@@ -51,19 +52,28 @@ static int io_reader(void * data, unsigned char *buf, size_t size, size_t *read)
51
52
  return 1;
52
53
  }
53
54
 
55
+ /* The parser calls back into Ruby for every event, so a handler can call
56
+ * Psych::Parser#parse again on the same object. parse() reinitialises the
57
+ * parser it is handed, which would pull the input out from under the loop
58
+ * still driving it, so keep a flag to reject a reentrant call. */
59
+ typedef struct {
60
+ yaml_parser_t yaml_parser;
61
+ int parsing;
62
+ } psych_parser_t;
63
+
54
64
  static void dealloc(void * ptr)
55
65
  {
56
- yaml_parser_t * parser;
66
+ psych_parser_t * parser;
57
67
 
58
- parser = (yaml_parser_t *)ptr;
59
- yaml_parser_delete(parser);
68
+ parser = (psych_parser_t *)ptr;
69
+ yaml_parser_delete(&parser->yaml_parser);
60
70
  xfree(parser);
61
71
  }
62
72
 
63
73
  #if 0
64
74
  static size_t memsize(const void *ptr)
65
75
  {
66
- const yaml_parser_t *parser = ptr;
76
+ const psych_parser_t *parser = ptr;
67
77
  /* TODO: calculate parser's size */
68
78
  return 0;
69
79
  }
@@ -80,10 +90,10 @@ static const rb_data_type_t psych_parser_type = {
80
90
 
81
91
  static VALUE allocate(VALUE klass)
82
92
  {
83
- yaml_parser_t * parser;
84
- VALUE obj = TypedData_Make_Struct(klass, yaml_parser_t, &psych_parser_type, parser);
93
+ psych_parser_t * parser;
94
+ VALUE obj = TypedData_Make_Struct(klass, psych_parser_t, &psych_parser_type, parser);
85
95
 
86
- yaml_parser_initialize(parser);
96
+ yaml_parser_initialize(&parser->yaml_parser);
87
97
 
88
98
  return obj;
89
99
  }
@@ -256,9 +266,22 @@ static VALUE protected_event_location(VALUE pointer)
256
266
  return rb_funcall3(args[0], id_event_location, 4, args + 1);
257
267
  }
258
268
 
259
- static VALUE parse(VALUE self, VALUE handler, VALUE yaml, VALUE path)
269
+ struct parse_args {
270
+ psych_parser_t * psych_parser;
271
+ VALUE self;
272
+ VALUE handler;
273
+ VALUE yaml;
274
+ VALUE path;
275
+ };
276
+
277
+ static VALUE parse_body(VALUE ptr)
260
278
  {
261
- yaml_parser_t * parser;
279
+ struct parse_args * pargs = (struct parse_args *)ptr;
280
+ yaml_parser_t * parser = &pargs->psych_parser->yaml_parser;
281
+ VALUE self = pargs->self;
282
+ VALUE handler = pargs->handler;
283
+ VALUE yaml = pargs->yaml;
284
+ VALUE path = pargs->path;
262
285
  yaml_event_t event;
263
286
  int done = 0;
264
287
  int state = 0;
@@ -266,8 +289,6 @@ static VALUE parse(VALUE self, VALUE handler, VALUE yaml, VALUE path)
266
289
  int encoding = rb_utf8_encindex();
267
290
  rb_encoding * internal_enc = rb_default_internal_encoding();
268
291
 
269
- TypedData_Get_Struct(self, yaml_parser_t, &psych_parser_type, parser);
270
-
271
292
  yaml_parser_delete(parser);
272
293
  yaml_parser_initialize(parser);
273
294
 
@@ -311,6 +332,10 @@ static VALUE parse(VALUE self, VALUE handler, VALUE yaml, VALUE path)
311
332
  event_args[3] = end_line;
312
333
  event_args[4] = end_column;
313
334
  rb_protect(protected_event_location, (VALUE)event_args, &state);
335
+ if (state) {
336
+ yaml_event_delete(&event);
337
+ rb_jump_tag(state);
338
+ }
314
339
 
315
340
  switch(event.type) {
316
341
  case YAML_STREAM_START_EVENT:
@@ -495,7 +520,11 @@ static VALUE parse(VALUE self, VALUE handler, VALUE yaml, VALUE path)
495
520
  rb_protect(protected_end_mapping, handler, &state);
496
521
  break;
497
522
  case YAML_NO_EVENT:
523
+ /* Once libyaml has produced the stream end, every later call
524
+ * succeeds with a zeroed event and YAML_STREAM_END_EVENT can no
525
+ * longer be reached. Stop rather than loop forever. */
498
526
  rb_protect(protected_empty, handler, &state);
527
+ done = 1;
499
528
  break;
500
529
  case YAML_STREAM_END_EVENT:
501
530
  rb_protect(protected_end_stream, handler, &state);
@@ -509,6 +538,37 @@ static VALUE parse(VALUE self, VALUE handler, VALUE yaml, VALUE path)
509
538
  return self;
510
539
  }
511
540
 
541
+ static VALUE parse_ensure(VALUE ptr)
542
+ {
543
+ psych_parser_t * parser = (psych_parser_t *)ptr;
544
+
545
+ parser->parsing = 0;
546
+
547
+ return Qnil;
548
+ }
549
+
550
+ static VALUE parse(VALUE self, VALUE handler, VALUE yaml, VALUE path)
551
+ {
552
+ psych_parser_t * parser;
553
+ struct parse_args pargs;
554
+
555
+ TypedData_Get_Struct(self, psych_parser_t, &psych_parser_type, parser);
556
+
557
+ if (parser->parsing) {
558
+ rb_raise(rb_const_get(mPsych, rb_intern("Exception")),
559
+ "parser is already parsing, it cannot be reused from a handler callback");
560
+ }
561
+ parser->parsing = 1;
562
+
563
+ pargs.psych_parser = parser;
564
+ pargs.self = self;
565
+ pargs.handler = handler;
566
+ pargs.yaml = yaml;
567
+ pargs.path = path;
568
+
569
+ return rb_ensure(parse_body, (VALUE)&pargs, parse_ensure, (VALUE)parser);
570
+ }
571
+
512
572
  /*
513
573
  * call-seq:
514
574
  * parser.mark # => #<Psych::Parser::Mark>
@@ -520,13 +580,13 @@ static VALUE mark(VALUE self)
520
580
  {
521
581
  VALUE mark_klass;
522
582
  VALUE args[3];
523
- yaml_parser_t * parser;
583
+ psych_parser_t * parser;
524
584
 
525
- TypedData_Get_Struct(self, yaml_parser_t, &psych_parser_type, parser);
585
+ TypedData_Get_Struct(self, psych_parser_t, &psych_parser_type, parser);
526
586
  mark_klass = rb_const_get_at(cPsychParser, rb_intern("Mark"));
527
- args[0] = SIZET2NUM(parser->mark.index);
528
- args[1] = SIZET2NUM(parser->mark.line);
529
- args[2] = SIZET2NUM(parser->mark.column);
587
+ args[0] = SIZET2NUM(parser->yaml_parser.mark.index);
588
+ args[1] = SIZET2NUM(parser->yaml_parser.mark.line);
589
+ args[2] = SIZET2NUM(parser->yaml_parser.mark.column);
530
590
 
531
591
  return rb_class_new_instance(3, args, mark_klass);
532
592
  }
@@ -559,7 +619,6 @@ void Init_psych_parser(void)
559
619
  rb_define_method(cPsychParser, "mark", mark, 0);
560
620
 
561
621
  id_read = rb_intern("read");
562
- id_path = rb_intern("path");
563
622
  id_empty = rb_intern("empty");
564
623
  id_start_stream = rb_intern("start_stream");
565
624
  id_end_stream = rb_intern("end_stream");
@@ -573,3 +632,5 @@ void Init_psych_parser(void)
573
632
  id_end_mapping = rb_intern("end_mapping");
574
633
  id_event_location = rb_intern("event_location");
575
634
  }
635
+
636
+ #endif /* PSYCH_USE_LIBFYAML */
@@ -9,6 +9,7 @@ module Psych
9
9
  DATA = 'Data' unless RUBY_VERSION < "3.2"
10
10
  DATE = 'Date'
11
11
  DATE_TIME = 'DateTime'
12
+ ENCODING = 'Encoding'
12
13
  EXCEPTION = 'Exception'
13
14
  OBJECT = 'Object'
14
15
  PSYCH_OMAP = 'Psych::Omap'
data/lib/psych/parser.rb CHANGED
@@ -59,7 +59,46 @@ module Psych
59
59
  # See Psych::Parser and Psych::Parser#handler
60
60
 
61
61
  def parse yaml, path = yaml.respond_to?(:path) ? yaml.path : "<unknown>"
62
- _native_parse @handler, yaml, path
62
+ _native_parse @handler, strip_bom(yaml), path
63
+ end
64
+
65
+ private
66
+
67
+ BOM = {
68
+ Encoding::UTF_8 => "\u{FEFF}".freeze,
69
+ Encoding::UTF_16LE => "\u{FEFF}".encode(Encoding::UTF_16LE).freeze,
70
+ Encoding::UTF_16BE => "\u{FEFF}".encode(Encoding::UTF_16BE).freeze,
71
+ Encoding::UTF_32LE => "\u{FEFF}".encode(Encoding::UTF_32LE).freeze,
72
+ Encoding::UTF_32BE => "\u{FEFF}".encode(Encoding::UTF_32BE).freeze,
73
+ }.freeze
74
+ private_constant :BOM
75
+
76
+ # libyaml only skips a leading byte order mark when it detects the stream
77
+ # encoding by itself. Psych passes the encoding explicitly whenever it is
78
+ # known, and on that path libyaml counts the BOM as a first-line character,
79
+ # which shifts the column of every token on the first line and silently
80
+ # terminates a block mapping at the second line [Bug #13615].
81
+ def strip_bom yaml
82
+ if String === yaml
83
+ bom = BOM[yaml.encoding]
84
+ # delete_prefix copies even when there is no prefix, so keep the guard.
85
+ return yaml.delete_prefix(bom) if bom && yaml.start_with?(bom)
86
+ elsif yaml.respond_to?(:read) && yaml.respond_to?(:external_encoding) &&
87
+ yaml.respond_to?(:pos) && yaml.respond_to?(:seek)
88
+ bom = BOM[yaml.external_encoding]
89
+ skip_io_bom yaml, bom.b if bom
90
+ end
91
+ yaml
92
+ end
93
+
94
+ def skip_io_bom io, bom
95
+ begin
96
+ pos = io.pos
97
+ rescue SystemCallError, IOError
98
+ return # Not seekable; nothing has been consumed yet.
99
+ end
100
+ head = io.read(bom.bytesize)
101
+ io.seek(pos, IO::SEEK_SET) if head && head.b != bom
63
102
  end
64
103
  end
65
104
  end
@@ -24,6 +24,18 @@ module Psych
24
24
  |[-+]?(?:0|[1-9](?:[0-9]|,[0-9]|_[0-9])*) (?# base 10)
25
25
  |[-+]?0x[_,]*[0-9a-fA-F][0-9a-fA-F_,]* (?# base 16))$/x
26
26
 
27
+ # YAML 1.1 treats yes/no/on/off as booleans in addition to true/false,
28
+ # while YAML 1.2's core schema only recognizes true/false. The default
29
+ # libyaml backend keeps the 1.1 set for backward compatibility; the
30
+ # experimental libfyaml backend follows 1.2.
31
+ if defined?(Psych::BACKEND) && Psych::BACKEND == 'libfyaml'
32
+ BOOLEAN_TRUE = /^true$/i
33
+ BOOLEAN_FALSE = /^false$/i
34
+ else
35
+ BOOLEAN_TRUE = /^(yes|true|on)$/i
36
+ BOOLEAN_FALSE = /^(no|false|off)$/i
37
+ end
38
+
27
39
  attr_reader :class_loader
28
40
 
29
41
  # Create a new scanner
@@ -48,9 +60,9 @@ module Psych
48
60
  string
49
61
  elsif string == '~' || string.match?(/^null$/i)
50
62
  nil
51
- elsif string.match?(/^(yes|true|on)$/i)
63
+ elsif string.match?(BOOLEAN_TRUE)
52
64
  true
53
- elsif string.match?(/^(no|false|off)$/i)
65
+ elsif string.match?(BOOLEAN_FALSE)
54
66
  false
55
67
  else
56
68
  string
@@ -115,7 +127,7 @@ module Psych
115
127
  def parse_time string
116
128
  klass = class_loader.load 'Time'
117
129
 
118
- date, time = *(string.split(/[ tT]/, 2))
130
+ date, time = *(string.split(/[Tt]|\s+/, 2))
119
131
  (yy, m, dd) = date.match(/^(-?\d{4})-(\d{1,2})-(\d{1,2})/).captures.map { |x| x.to_i }
120
132
  md = time.match(/(\d+:\d+:\d+)(?:\.(\d*))?\s*(Z|[-+]\d+(:\d\d)?)?/)
121
133
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Psych
4
4
  # The version of Psych you are using
5
- VERSION = '5.4.0'
5
+ VERSION = '5.5.0'
6
6
 
7
7
  if RUBY_ENGINE == 'jruby'
8
8
  DEFAULT_SNAKEYAML_VERSION = '2.10'.freeze
@@ -72,7 +72,7 @@ module Psych
72
72
  when '!binary', 'tag:yaml.org,2002:binary'
73
73
  o.value.unpack('m').first
74
74
  when /^!(?:str|ruby\/string)(?::(.*))?$/, 'tag:yaml.org,2002:str'
75
- klass = resolve_class($1)
75
+ klass = resolve_subclass($1, String)
76
76
  if klass
77
77
  klass.allocate.replace o.value
78
78
  else
@@ -87,6 +87,7 @@ module Psych
87
87
  DateTime.civil(*t.to_a[0, 6].reverse, Rational(t.utc_offset, 86400)) +
88
88
  (t.subsec/86400)
89
89
  when '!ruby/encoding'
90
+ class_loader.encoding
90
91
  ::Encoding.find o.value
91
92
  when "!ruby/object:Complex"
92
93
  class_loader.complex
@@ -156,7 +157,7 @@ module Psych
156
157
  }
157
158
  map
158
159
  when /^!(?:seq|ruby\/array):(.*)$/
159
- klass = resolve_class($1)
160
+ klass = resolve_subclass($1, Array)
160
161
  list = register(o, klass.allocate)
161
162
  o.children.each { |c| list.push accept c }
162
163
  list
@@ -246,7 +247,7 @@ module Psych
246
247
  end
247
248
 
248
249
  when /^!(?:str|ruby\/string)(?::(.*))?$/, 'tag:yaml.org,2002:str'
249
- klass = resolve_class($1)
250
+ klass = resolve_subclass($1, String)
250
251
  members = {}
251
252
  string = nil
252
253
 
@@ -267,7 +268,7 @@ module Psych
267
268
  end
268
269
  init_with(string, members.map { |k,v| [k.to_s.sub(/^@/, ''),v] }, o)
269
270
  when /^!ruby\/array:(.*)$/
270
- klass = resolve_class($1)
271
+ klass = resolve_subclass($1, Array)
271
272
  list = register(o, klass.allocate)
272
273
 
273
274
  members = Hash[o.children.map { |c| accept c }.each_slice(2).to_a]
@@ -301,7 +302,7 @@ module Psych
301
302
  set
302
303
 
303
304
  when /^!ruby\/hash-with-ivars(?::(.*))?$/
304
- hash = $1 ? resolve_class($1).allocate : {}
305
+ hash = $1 ? resolve_subclass($1, Hash).allocate : {}
305
306
  register o, hash
306
307
  o.children.each_slice(2) do |key, value|
307
308
  case key.value
@@ -316,7 +317,7 @@ module Psych
316
317
  hash
317
318
 
318
319
  when /^!map:(.*)$/, /^!ruby\/hash:(.*)$/
319
- revive_hash register(o, resolve_class($1).allocate), o
320
+ revive_hash register(o, resolve_subclass($1, Hash).allocate), o
320
321
 
321
322
  when '!omap', 'tag:yaml.org,2002:omap'
322
323
  map = register(o, class_loader.psych_omap.new)
@@ -444,9 +445,6 @@ module Psych
444
445
  end
445
446
  end
446
447
 
447
- def merge_key hash, key, val
448
- end
449
-
450
448
  def revive klass, node
451
449
  s = register(node, klass.allocate)
452
450
  init_with(s, revive_hash({}, node, true), node)
@@ -468,6 +466,19 @@ module Psych
468
466
  def resolve_class klassname
469
467
  class_loader.load klassname
470
468
  end
469
+
470
+ # Resolve +klassname+ and ensure it is +parent+ or one of its
471
+ # subclasses. Tags such as !ruby/hash-with-ivars are only ever emitted
472
+ # for subclasses of a specific core class; without this check a crafted
473
+ # document could name an unrelated (but permitted) class and have its
474
+ # state populated directly, bypassing the class's own init_with.
475
+ def resolve_subclass klassname, parent
476
+ klass = resolve_class(klassname)
477
+ if klass && !(klass <= parent)
478
+ raise ArgumentError, "Invalid tag: expected a subclass of #{parent}, got #{klass}"
479
+ end
480
+ klass
481
+ end
471
482
  end
472
483
 
473
484
  class NoAliasRuby < ToRuby
@@ -496,9 +496,6 @@ module Psych
496
496
  end
497
497
  end
498
498
 
499
- def dump_list o
500
- end
501
-
502
499
  def dump_exception o, msg
503
500
  tag = ['!ruby/exception', o.class.name].join ':'
504
501
 
data/lib/psych.jar CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: psych
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.4.0
4
+ version: 5.5.0
5
5
  platform: java
6
6
  authors:
7
7
  - Aaron Patterson
@@ -133,7 +133,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
133
133
  version: '0'
134
134
  requirements:
135
135
  - jar org.snakeyaml:snakeyaml-engine, 2.10
136
- rubygems_version: 4.0.3
136
+ rubygems_version: 4.0.19
137
137
  specification_version: 4
138
138
  summary: Psych is a YAML parser and emitter
139
139
  test_files: []