syck 1.6.0 → 1.6.1

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: 840b03fd443a2db94f3eb4a5a0d4b20b6d5292ce4be81f2d2390b5f23aef3f97
4
- data.tar.gz: cfb7139004022b747e170e46d54c39aaecd7468ea1d3bfe6a5dba5eb18555fc9
3
+ metadata.gz: a6f8be592c6d196af5a6fbf7bdab813819b4303d817f48b2edbc2e3441362382
4
+ data.tar.gz: 309adadd5621cfecdee15f0e36e39b7c1205df6406ab2521cea915b7509196fb
5
5
  SHA512:
6
- metadata.gz: 07f844fab0e7d8fbcffc9df0b28701ffd29ed1d9fd5f2d433e65fbcfc2ed437d4a340b79591f69eb0bf8cd1d0a4e030a408ccdc80626a681821489944691e02a
7
- data.tar.gz: c959e3ee17666ac383ee92d7f27ea2e6ddd037a7f7ec3b9b17cc6385ef53f533bc190af1a75efad4b01ae190f50eb9873bf2f29e7058f0c3273885b8c25335c6
6
+ metadata.gz: ef57afc974162ffda31cf27709ed5bdad7219f0a181a95a833549d575bfd0edd8fb18967ce380120b477107a643f823294ca83092f17b93a518e49ae59961288
7
+ data.tar.gz: abbdbea1f6eaea32d639b8ea9bcaee50c012c2f362d24d7a49489938eb079eb5c813d437bbf002cdb2ff149d323fd7510db3494075f6bb6c9a0f9884ed87a485
data/ext/syck/implicit.c CHANGED
@@ -11,7 +11,7 @@
11
11
  #include "ruby/ruby.h"
12
12
  #include "syck.h"
13
13
 
14
- #define YYCTYPE char
14
+ #define YYCTYPE unsigned char
15
15
  #define YYCURSOR cursor
16
16
  #define YYMARKER marker
17
17
  #define YYLIMIT limit
data/ext/syck/rubyext.c CHANGED
@@ -13,29 +13,6 @@
13
13
  #include <sys/types.h>
14
14
  #include <time.h>
15
15
 
16
- typedef struct RVALUE {
17
- union {
18
- #if 0
19
- struct {
20
- unsigned long flags; /* always 0 for freed obj */
21
- struct RVALUE *next;
22
- } free;
23
- #endif
24
- struct RBasic basic;
25
- struct RObject object;
26
- /*struct RClass klass;*/
27
- /*struct RFloat flonum;*/
28
- /*struct RString string;*/
29
- struct RArray array;
30
- /*struct RRegexp regexp;*/
31
- /*struct RHash hash;*/
32
- /*struct RData data;*/
33
- /*struct RStruct rstruct;*/
34
- /*struct RBignum bignum;*/
35
- /*struct RFile file;*/
36
- } as;
37
- } RVALUE;
38
-
39
16
  typedef struct {
40
17
  long hash;
41
18
  char *buffer;
@@ -705,6 +682,99 @@ yaml_org_handler( SyckNode *n, VALUE *ref )
705
682
  }
706
683
 
707
684
  static void syck_node_mark( SyckNode *n );
685
+ static VALUE id_hash_new(void);
686
+
687
+ /*
688
+ * Rewrite every reference to `from` inside `obj` so it points at `to`.
689
+ *
690
+ * A self-referential anchor (`--- &a\n- *a\n`) is aliased before the anchored
691
+ * node is finished, so the parser hands out a BadAlias placeholder and only
692
+ * later learns which object the anchor really is. Only containers can hold a
693
+ * placeholder, so the walk stops at anything else. `seen` must compare by
694
+ * identity, otherwise equal-but-distinct nodes collapse and cycles that are
695
+ * already in place would recurse forever.
696
+ */
697
+ static void
698
+ syck_swap_placeholder(VALUE obj, VALUE from, VALUE to, VALUE seen)
699
+ {
700
+ long i;
701
+ VALUE ivars;
702
+
703
+ if ( SPECIAL_CONST_P( obj ) || OBJ_FROZEN( obj ) ) return;
704
+
705
+ switch ( BUILTIN_TYPE( obj ) )
706
+ {
707
+ case T_ARRAY:
708
+ case T_HASH:
709
+ case T_STRUCT:
710
+ case T_OBJECT:
711
+ break;
712
+
713
+ default:
714
+ return;
715
+ }
716
+
717
+ if ( RTEST( rb_hash_lookup( seen, obj ) ) ) return;
718
+ rb_hash_aset( seen, obj, Qtrue );
719
+
720
+ switch ( BUILTIN_TYPE( obj ) )
721
+ {
722
+ case T_ARRAY:
723
+ for ( i = 0; i < RARRAY_LEN( obj ); i++ )
724
+ {
725
+ VALUE v = rb_ary_entry( obj, i );
726
+ if ( v == from ) rb_ary_store( obj, i, to );
727
+ else syck_swap_placeholder( v, from, to, seen );
728
+ }
729
+ break;
730
+
731
+ case T_HASH:
732
+ {
733
+ VALUE keys = rb_funcall( obj, s_keys, 0 );
734
+ for ( i = 0; i < RARRAY_LEN( keys ); i++ )
735
+ {
736
+ VALUE key = rb_ary_entry( keys, i );
737
+ VALUE val = rb_hash_aref( obj, key );
738
+
739
+ if ( key == from || val == from )
740
+ {
741
+ VALUE new_key = key == from ? to : key;
742
+ VALUE new_val = val == from ? to : val;
743
+
744
+ if ( new_key != key ) rb_hash_delete( obj, key );
745
+ rb_hash_aset( obj, new_key, new_val );
746
+ key = new_key;
747
+ val = new_val;
748
+ }
749
+
750
+ syck_swap_placeholder( key, from, to, seen );
751
+ syck_swap_placeholder( val, from, to, seen );
752
+ }
753
+ }
754
+ break;
755
+
756
+ case T_STRUCT:
757
+ for ( i = 0; i < RSTRUCT_LEN( obj ); i++ )
758
+ {
759
+ VALUE v = rb_struct_aref( obj, LONG2NUM( i ) );
760
+ if ( v == from ) rb_struct_aset( obj, LONG2NUM( i ), to );
761
+ else syck_swap_placeholder( v, from, to, seen );
762
+ }
763
+ break;
764
+
765
+ default:
766
+ break;
767
+ }
768
+
769
+ ivars = rb_obj_instance_variables( obj );
770
+ for ( i = 0; i < RARRAY_LEN( ivars ); i++ )
771
+ {
772
+ ID name = SYM2ID( rb_ary_entry( ivars, i ) );
773
+ VALUE v = rb_ivar_get( obj, name );
774
+ if ( v == from ) rb_ivar_set( obj, name, to );
775
+ else syck_swap_placeholder( v, from, to, seen );
776
+ }
777
+ }
708
778
 
709
779
  /*
710
780
  * {native mode} node handler
@@ -738,13 +808,19 @@ rb_syck_load_handler(SyckParser *p, SyckNode *n)
738
808
  DATA_PTR( node_wrapper ) = NULL;
739
809
 
740
810
  /*
741
- * ID already set, let's alter the symbol table to accept the new object
811
+ * A placeholder was handed out for this node while it was still being
812
+ * parsed. Syck used to fuse the two by copying the real object over the
813
+ * placeholder's heap slot, which is wrong on every count the GC cares
814
+ * about: the slot is sized for the placeholder, the copied flags carry
815
+ * the source object's age bits, no write barrier fires, and zeroing the
816
+ * source turns a live object into T_NONE behind the GC's back. The heap
817
+ * then stays corrupted until some unrelated allocation crashes. Rewrite
818
+ * the references instead.
742
819
  */
743
820
  if (n->id > 0 && !NIL_P(obj))
744
821
  {
745
- MEMCPY((void *)n->id, (void *)obj, RVALUE, 1);
746
- MEMZERO((void *)obj, RVALUE, 1);
747
- obj = n->id;
822
+ syck_swap_placeholder( obj, (VALUE)n->id, obj, id_hash_new() );
823
+ n->id = obj;
748
824
  }
749
825
 
750
826
  if ( bonus->taint) OBJ_TAINT( obj );
@@ -6,7 +6,7 @@ module Syck
6
6
  #
7
7
  # Constants
8
8
  #
9
- VERSION = '1.6.0'
9
+ VERSION = '1.6.1'
10
10
  SUPPORTED_YAML_VERSIONS = ['1.0']
11
11
 
12
12
  #
data/test/test_boolean.rb CHANGED
@@ -32,5 +32,17 @@ module Syck
32
32
  assert_equal "n", Syck.load("--- n")
33
33
  assert_equal "N", Syck.load("--- N")
34
34
  end
35
+
36
+ ###
37
+ # https://github.com/ruby/syck/issues/22
38
+ # A boolean-like prefix followed by a non-ASCII byte must not be
39
+ # matched as a boolean
40
+ def test_bool_prefix_with_non_ascii
41
+ assert_equal "Noémie", Syck.load("--- Noémie")
42
+ assert_equal ["Noémie"], Syck.load("--- [Noémie]")
43
+ assert_equal "Yeså", Syck.load("--- Yeså")
44
+ assert_equal "trueé", Syck.load("--- trueé")
45
+ assert_equal "nullé", Syck.load("--- nullé")
46
+ end
35
47
  end
36
48
  end
data/test/test_yaml.rb CHANGED
@@ -1337,6 +1337,40 @@ EOY
1337
1337
  assert_equal( inspect_str, Syck::load( a.to_yaml ).inspect )
1338
1338
  end
1339
1339
 
1340
+ #
1341
+ # A self-referential anchor is aliased before the anchored node exists, so
1342
+ # the parser hands out a placeholder and patches it up afterwards. That
1343
+ # used to be done by overwriting the placeholder's heap slot, which left
1344
+ # the GC heap corrupted and crashed at some later allocation.
1345
+ #
1346
+ def test_self_referential_anchor
1347
+ [ 1, 3, 6, 50 ].each do |n|
1348
+ seq = Syck::load( "--- &id001\n" + "- *id001\n" * n )
1349
+ assert_equal( n, seq.size )
1350
+ seq.each { |item| assert_same( seq, item ) }
1351
+ end
1352
+
1353
+ map = Syck::load( "--- &id001\nself: *id001\n" )
1354
+ assert_same( map, map["self"] )
1355
+
1356
+ keyed = Syck::load( "--- &id001\n? *id001\n: 1\n" )
1357
+ assert_same( keyed, keyed.keys.first )
1358
+
1359
+ # The alias appears as a key and again below the matching value, so
1360
+ # rewriting the key must not stop the walk from reaching the rest.
1361
+ both = Syck::load( "--- &id001\n? *id001\n: \n - *id001\n" )
1362
+ key, value = both.first
1363
+ assert_same( both, key )
1364
+ assert_same( both, value[0] )
1365
+
1366
+ nested = Syck::load( "--- &id001\n- &id002\n - *id001\n- *id002\n" )
1367
+ assert_same( nested, nested[0][0] )
1368
+ assert_same( nested[0], nested[1] )
1369
+
1370
+ GC.start
1371
+ assert_nothing_raised { GC.verify_internal_consistency }
1372
+ end
1373
+
1340
1374
  #
1341
1375
  # Test Symbol cycle
1342
1376
  #
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: syck
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.0
4
+ version: 1.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hiroshi SHIBATA