syck 1.6.0 → 1.6.2
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 +4 -4
- data/ext/syck/implicit.c +1 -1
- data/ext/syck/rubyext.c +124 -36
- data/lib/syck/constants.rb +1 -1
- data/test/test_boolean.rb +12 -0
- data/test/test_large_input.rb +26 -0
- data/test/test_yaml.rb +34 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e27c3b9b21ba6e707479bdbfeadbd583d68cfef4b6f2e4882faff6316fc09f19
|
|
4
|
+
data.tar.gz: d5bfc236838cee8709f19789e641eadf9c218e39b668db1462a5a704cea444b3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4f5de63e2fcd1c793fc25049c3cc36d7fcbb30c661f74b41af5e2f13cdca7145d99820812c6a3729a627810286c2a70b318e3ff2f252f9620514dad9f099ae0f
|
|
7
|
+
data.tar.gz: a98dbb0151212292f8d2cc47ef00730b607fb0032427c0eec333a66a4b52872429f8c85e9e9aa3effc1ae716cf24e92be7920f9ee68bf556021cc3d2955dfdf6
|
data/ext/syck/implicit.c
CHANGED
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;
|
|
@@ -171,6 +148,7 @@ rb_syck_compile(VALUE self, VALUE port)
|
|
|
171
148
|
SYMID oid;
|
|
172
149
|
int taint;
|
|
173
150
|
char *ret;
|
|
151
|
+
long blen;
|
|
174
152
|
VALUE bc;
|
|
175
153
|
bytestring_t *sav = NULL;
|
|
176
154
|
void *data = NULL;
|
|
@@ -183,18 +161,25 @@ rb_syck_compile(VALUE self, VALUE port)
|
|
|
183
161
|
syck_parser_taguri_expansion( parser, 0 );
|
|
184
162
|
oid = syck_parse( parser );
|
|
185
163
|
if (!syck_lookup_sym( parser, oid, &data )) {
|
|
164
|
+
syck_free_parser( parser );
|
|
186
165
|
rb_raise(rb_eSyntaxError, "root node <%p> not found", (void *)oid);
|
|
187
166
|
}
|
|
188
167
|
sav = data;
|
|
189
168
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
169
|
+
/*
|
|
170
|
+
* Steal the buffer from the parser's symbol table (S_FREE ignores
|
|
171
|
+
* the NULLed pointer) so the parser can be freed before rb_str_new,
|
|
172
|
+
* which may raise and would otherwise leak the parser.
|
|
173
|
+
*/
|
|
174
|
+
ret = sav->buffer;
|
|
175
|
+
sav->buffer = NULL;
|
|
195
176
|
syck_free_parser( parser );
|
|
196
177
|
|
|
197
|
-
|
|
178
|
+
blen = (long)strlen( ret );
|
|
179
|
+
bc = rb_str_new( 0, blen + 2 );
|
|
180
|
+
memcpy( RSTRING_PTR(bc), "D\n", 2 );
|
|
181
|
+
memcpy( RSTRING_PTR(bc) + 2, ret, (size_t)blen );
|
|
182
|
+
S_FREE( ret );
|
|
198
183
|
if ( taint ) OBJ_TAINT( bc );
|
|
199
184
|
return bc;
|
|
200
185
|
}
|
|
@@ -705,6 +690,99 @@ yaml_org_handler( SyckNode *n, VALUE *ref )
|
|
|
705
690
|
}
|
|
706
691
|
|
|
707
692
|
static void syck_node_mark( SyckNode *n );
|
|
693
|
+
static VALUE id_hash_new(void);
|
|
694
|
+
|
|
695
|
+
/*
|
|
696
|
+
* Rewrite every reference to `from` inside `obj` so it points at `to`.
|
|
697
|
+
*
|
|
698
|
+
* A self-referential anchor (`--- &a\n- *a\n`) is aliased before the anchored
|
|
699
|
+
* node is finished, so the parser hands out a BadAlias placeholder and only
|
|
700
|
+
* later learns which object the anchor really is. Only containers can hold a
|
|
701
|
+
* placeholder, so the walk stops at anything else. `seen` must compare by
|
|
702
|
+
* identity, otherwise equal-but-distinct nodes collapse and cycles that are
|
|
703
|
+
* already in place would recurse forever.
|
|
704
|
+
*/
|
|
705
|
+
static void
|
|
706
|
+
syck_swap_placeholder(VALUE obj, VALUE from, VALUE to, VALUE seen)
|
|
707
|
+
{
|
|
708
|
+
long i;
|
|
709
|
+
VALUE ivars;
|
|
710
|
+
|
|
711
|
+
if ( SPECIAL_CONST_P( obj ) || OBJ_FROZEN( obj ) ) return;
|
|
712
|
+
|
|
713
|
+
switch ( BUILTIN_TYPE( obj ) )
|
|
714
|
+
{
|
|
715
|
+
case T_ARRAY:
|
|
716
|
+
case T_HASH:
|
|
717
|
+
case T_STRUCT:
|
|
718
|
+
case T_OBJECT:
|
|
719
|
+
break;
|
|
720
|
+
|
|
721
|
+
default:
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
if ( RTEST( rb_hash_lookup( seen, obj ) ) ) return;
|
|
726
|
+
rb_hash_aset( seen, obj, Qtrue );
|
|
727
|
+
|
|
728
|
+
switch ( BUILTIN_TYPE( obj ) )
|
|
729
|
+
{
|
|
730
|
+
case T_ARRAY:
|
|
731
|
+
for ( i = 0; i < RARRAY_LEN( obj ); i++ )
|
|
732
|
+
{
|
|
733
|
+
VALUE v = rb_ary_entry( obj, i );
|
|
734
|
+
if ( v == from ) rb_ary_store( obj, i, to );
|
|
735
|
+
else syck_swap_placeholder( v, from, to, seen );
|
|
736
|
+
}
|
|
737
|
+
break;
|
|
738
|
+
|
|
739
|
+
case T_HASH:
|
|
740
|
+
{
|
|
741
|
+
VALUE keys = rb_funcall( obj, s_keys, 0 );
|
|
742
|
+
for ( i = 0; i < RARRAY_LEN( keys ); i++ )
|
|
743
|
+
{
|
|
744
|
+
VALUE key = rb_ary_entry( keys, i );
|
|
745
|
+
VALUE val = rb_hash_aref( obj, key );
|
|
746
|
+
|
|
747
|
+
if ( key == from || val == from )
|
|
748
|
+
{
|
|
749
|
+
VALUE new_key = key == from ? to : key;
|
|
750
|
+
VALUE new_val = val == from ? to : val;
|
|
751
|
+
|
|
752
|
+
if ( new_key != key ) rb_hash_delete( obj, key );
|
|
753
|
+
rb_hash_aset( obj, new_key, new_val );
|
|
754
|
+
key = new_key;
|
|
755
|
+
val = new_val;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
syck_swap_placeholder( key, from, to, seen );
|
|
759
|
+
syck_swap_placeholder( val, from, to, seen );
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
break;
|
|
763
|
+
|
|
764
|
+
case T_STRUCT:
|
|
765
|
+
for ( i = 0; i < RSTRUCT_LEN( obj ); i++ )
|
|
766
|
+
{
|
|
767
|
+
VALUE v = rb_struct_aref( obj, LONG2NUM( i ) );
|
|
768
|
+
if ( v == from ) rb_struct_aset( obj, LONG2NUM( i ), to );
|
|
769
|
+
else syck_swap_placeholder( v, from, to, seen );
|
|
770
|
+
}
|
|
771
|
+
break;
|
|
772
|
+
|
|
773
|
+
default:
|
|
774
|
+
break;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
ivars = rb_obj_instance_variables( obj );
|
|
778
|
+
for ( i = 0; i < RARRAY_LEN( ivars ); i++ )
|
|
779
|
+
{
|
|
780
|
+
ID name = SYM2ID( rb_ary_entry( ivars, i ) );
|
|
781
|
+
VALUE v = rb_ivar_get( obj, name );
|
|
782
|
+
if ( v == from ) rb_ivar_set( obj, name, to );
|
|
783
|
+
else syck_swap_placeholder( v, from, to, seen );
|
|
784
|
+
}
|
|
785
|
+
}
|
|
708
786
|
|
|
709
787
|
/*
|
|
710
788
|
* {native mode} node handler
|
|
@@ -738,13 +816,19 @@ rb_syck_load_handler(SyckParser *p, SyckNode *n)
|
|
|
738
816
|
DATA_PTR( node_wrapper ) = NULL;
|
|
739
817
|
|
|
740
818
|
/*
|
|
741
|
-
*
|
|
819
|
+
* A placeholder was handed out for this node while it was still being
|
|
820
|
+
* parsed. Syck used to fuse the two by copying the real object over the
|
|
821
|
+
* placeholder's heap slot, which is wrong on every count the GC cares
|
|
822
|
+
* about: the slot is sized for the placeholder, the copied flags carry
|
|
823
|
+
* the source object's age bits, no write barrier fires, and zeroing the
|
|
824
|
+
* source turns a live object into T_NONE behind the GC's back. The heap
|
|
825
|
+
* then stays corrupted until some unrelated allocation crashes. Rewrite
|
|
826
|
+
* the references instead.
|
|
742
827
|
*/
|
|
743
828
|
if (n->id > 0 && !NIL_P(obj))
|
|
744
829
|
{
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
obj = n->id;
|
|
830
|
+
syck_swap_placeholder( obj, (VALUE)n->id, obj, id_hash_new() );
|
|
831
|
+
n->id = obj;
|
|
748
832
|
}
|
|
749
833
|
|
|
750
834
|
if ( bonus->taint) OBJ_TAINT( obj );
|
|
@@ -1137,13 +1221,17 @@ syck_set_ivars(
|
|
|
1137
1221
|
)
|
|
1138
1222
|
{
|
|
1139
1223
|
VALUE ivname = rb_ary_entry( vars, 0 );
|
|
1224
|
+
VALUE ivn_v;
|
|
1140
1225
|
char *ivn;
|
|
1226
|
+
long ivn_len;
|
|
1141
1227
|
StringValue( ivname );
|
|
1142
|
-
|
|
1228
|
+
ivn_len = RSTRING_LEN(ivname);
|
|
1229
|
+
ivn = ALLOCV_N( char, ivn_v, ivn_len + 2 );
|
|
1143
1230
|
ivn[0] = '@';
|
|
1144
|
-
ivn
|
|
1145
|
-
|
|
1231
|
+
memcpy( ivn + 1, RSTRING_PTR(ivname), (size_t)ivn_len );
|
|
1232
|
+
ivn[ivn_len + 1] = '\0';
|
|
1146
1233
|
rb_iv_set( obj, ivn, rb_ary_entry( vars, 1 ) );
|
|
1234
|
+
ALLOCV_END( ivn_v );
|
|
1147
1235
|
return Qnil;
|
|
1148
1236
|
}
|
|
1149
1237
|
|
data/lib/syck/constants.rb
CHANGED
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
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'helper'
|
|
2
|
+
|
|
3
|
+
module Syck
|
|
4
|
+
# Both of these sized an `alloca` from the document. They are run on a Thread
|
|
5
|
+
# because a Ruby thread's stack is far smaller than the main stack, which is
|
|
6
|
+
# the shape a web or job worker actually has.
|
|
7
|
+
class TestLargeInput < Test::Unit::TestCase
|
|
8
|
+
SIZE = 4 * 1024 * 1024
|
|
9
|
+
|
|
10
|
+
def on_thread
|
|
11
|
+
Thread.new { yield }.value
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_long_ivar_name
|
|
15
|
+
doc = "--- !ruby/object:Object\n" + ('n' * SIZE) + ": 1\n"
|
|
16
|
+
obj = on_thread { Syck.load(doc) }
|
|
17
|
+
assert_equal 1, obj.instance_variable_get("@#{'n' * SIZE}")
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def test_long_compile_input
|
|
21
|
+
doc = "--- \n" + (0...(SIZE / 20)).map { |i| "k#{i}: v#{i}\n" }.join
|
|
22
|
+
bc = on_thread { Syck.compile(doc) }
|
|
23
|
+
assert_equal "D\n", bc[0, 2]
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
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.
|
|
4
|
+
version: 1.6.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Hiroshi SHIBATA
|
|
@@ -107,6 +107,7 @@ files:
|
|
|
107
107
|
- test/test_exception.rb
|
|
108
108
|
- test/test_gc.rb
|
|
109
109
|
- test/test_hash.rb
|
|
110
|
+
- test/test_large_input.rb
|
|
110
111
|
- test/test_null.rb
|
|
111
112
|
- test/test_omap.rb
|
|
112
113
|
- test/test_set.rb
|
|
@@ -147,6 +148,7 @@ test_files:
|
|
|
147
148
|
- test/test_exception.rb
|
|
148
149
|
- test/test_gc.rb
|
|
149
150
|
- test/test_hash.rb
|
|
151
|
+
- test/test_large_input.rb
|
|
150
152
|
- test/test_null.rb
|
|
151
153
|
- test/test_omap.rb
|
|
152
154
|
- test/test_set.rb
|