yeptris 0.6.15.1-aarch64-linux → 0.6.15.2-aarch64-linux
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/lib/yeptris/document.rb +14 -8
- data/lib/yeptris/materializer.rb +5 -1
- data/lib/yeptris/node.rb +9 -0
- data/lib/yeptris/psych/visitors.rb +31 -5
- data/lib/yeptris/psych.rb +14 -7
- data/lib/yeptris.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 419470a0e038bec65880a3d764da46f072d7993e5aca9de71825a8428d5b2f98
|
|
4
|
+
data.tar.gz: 19cf714c7f80abc07d8729420700ef2c08bf1a140de03c3e11a8bb6ff177a4f4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9d11c53e5305c76f780f431d73be9c62228e250ab164c4fd636429ad4fca4e3705b1d46b0e9cf7abed5d8a0662d0347a2399de0ce3a16f5eec987d05d0fb053f
|
|
7
|
+
data.tar.gz: 5c24e95902b4ae44595710274ede3efbd605885d8cbc0747fc0965fcb8a2addb32ea8f18648606fef823d09a6f106d777d175f4e8ed0f1c8e74810f22d6cbee6
|
data/lib/yeptris/document.rb
CHANGED
|
@@ -20,7 +20,7 @@ class Yeptris::Document
|
|
|
20
20
|
# always yields the same Ruby object (identity for aliases/eql?),
|
|
21
21
|
# cleared at free — no stale entries, no GC-race weak maps.
|
|
22
22
|
@wrapper_cache = {}
|
|
23
|
-
ObjectSpace.define_finalizer(self, self.class.finalize(c_ptr
|
|
23
|
+
ObjectSpace.define_finalizer(self, self.class.finalize(c_ptr)) unless c_ptr.null?
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def self.parse(yaml, schema: :core_12, max_depth: 0)
|
|
@@ -88,6 +88,9 @@ class Yeptris::Document
|
|
|
88
88
|
return if @freed.state == :freed
|
|
89
89
|
|
|
90
90
|
@freed.state = :freed
|
|
91
|
+
# stop the GC finalizer BEFORE the C free — it captures the same
|
|
92
|
+
# pointer, and its firing after this free is the double free
|
|
93
|
+
ObjectSpace.undefine_finalizer(self)
|
|
91
94
|
@wrapper_cache.clear
|
|
92
95
|
Yeptris::FFI.yeptris_document_free(@c_ptr)
|
|
93
96
|
end
|
|
@@ -221,12 +224,15 @@ class Yeptris::Document
|
|
|
221
224
|
self
|
|
222
225
|
end
|
|
223
226
|
|
|
224
|
-
# GC safety net:
|
|
225
|
-
#
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
227
|
+
# GC safety net (#182): the proc captures ONLY the raw pointer — no
|
|
228
|
+
# Ruby objects, no wrapper, no freed-flag struct. A finalizer that
|
|
229
|
+
# closes over the owning wrapper races that wrapper's own sweep
|
|
230
|
+
# (the classic use-after-free: freed?/free against half-collected
|
|
231
|
+
# ivars, then a garbage C pointer into yeptris_document_free →
|
|
232
|
+
# SIGABRT). Explicit #free undefines this finalizer BEFORE the C
|
|
233
|
+
# free, so the double free cannot happen; finalizers run on the
|
|
234
|
+
# main thread, so there is no cross-thread window.
|
|
235
|
+
def self.finalize(c_ptr)
|
|
236
|
+
proc { Yeptris::FFI.yeptris_document_free(c_ptr) }
|
|
231
237
|
end
|
|
232
238
|
end
|
data/lib/yeptris/materializer.rb
CHANGED
|
@@ -115,7 +115,11 @@ module Yeptris
|
|
|
115
115
|
end
|
|
116
116
|
|
|
117
117
|
def parse_timestamp(v)
|
|
118
|
-
|
|
118
|
+
# stdlib scalar_scanner: date-only strings parse with
|
|
119
|
+
# strptime('%F', Date::GREGORIAN) — the PROLEPTIC calendar —
|
|
120
|
+
# not Date.parse's default ITALY reform (a 1582 cycle fails
|
|
121
|
+
# the ported test_julian_date otherwise)
|
|
122
|
+
return ::Date.strptime(v, "%F", ::Date::GREGORIAN) unless v.match?(/[Tt ]\d/)
|
|
119
123
|
|
|
120
124
|
# normalize the YAML 1.1 space forms onto iso8601 for
|
|
121
125
|
# xmlschema: "2001-12-14 21:59:43.10 -05:00" ->
|
data/lib/yeptris/node.rb
CHANGED
|
@@ -394,6 +394,15 @@ class Yeptris::Node
|
|
|
394
394
|
def scalar_to_ruby
|
|
395
395
|
return symbolize if symbol? && tag_id == :str
|
|
396
396
|
|
|
397
|
+
# stdlib deserialize's tagged-scalar arms: the class tag carries
|
|
398
|
+
# DateTime (dumped tagged — a plain timestamp re-loads as Time)
|
|
399
|
+
if tag == "!ruby/object:DateTime"
|
|
400
|
+
ts = value.to_s.sub(/ (\d)/, 'T\\1').sub(/ ([+-]\d)/, '\\1')
|
|
401
|
+
t = ::Time.xmlschema(ts)
|
|
402
|
+
return ::DateTime.civil(t.year, t.month, t.day, t.hour, t.min, t.sec,
|
|
403
|
+
Rational(t.utc_offset, 86_400)) + Rational(t.subsec, 86_400)
|
|
404
|
+
end
|
|
405
|
+
|
|
397
406
|
case tag_id
|
|
398
407
|
when :null then nil
|
|
399
408
|
when :bool then to_bool
|
|
@@ -66,11 +66,34 @@ module Yeptris
|
|
|
66
66
|
end
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
+
# stdlib register()s every object — scalars included — so a
|
|
70
|
+
# repeated scalar dumps &name/*name (test_float_references,
|
|
71
|
+
# test_alias_with_time). Containers already route through
|
|
72
|
+
# anchor_for; this is the scalar arm of the same machinery.
|
|
73
|
+
def anchored_scalar(obj, text: nil, tag: nil)
|
|
74
|
+
state, name = anchor_for(obj)
|
|
75
|
+
return alias_of(obj, name) if state == :alias
|
|
76
|
+
|
|
77
|
+
n = scalar(text || obj, tag: tag)
|
|
78
|
+
n.set_anchor(name) if name
|
|
79
|
+
remember(obj, n)
|
|
80
|
+
n
|
|
81
|
+
end
|
|
82
|
+
|
|
69
83
|
def visit(obj)
|
|
70
84
|
case obj
|
|
85
|
+
# strings/floats/ints: stdlib yaml_tree does NOT anchor them
|
|
86
|
+
# (its float test is load-side only) — and CBOR encode
|
|
87
|
+
# rejects the anchors the cbor profile feeds it
|
|
71
88
|
when nil, true, false, ::Integer, ::Float, ::String then scalar(obj)
|
|
72
89
|
when ::Symbol then @tree.new_scalar(":#{obj}", :plain) # psych emits symbols bare, never through visit_String's quoting rules
|
|
73
|
-
|
|
90
|
+
# stdlib visit_DateTime: the class tag carries the type (a
|
|
91
|
+
# plain timestamp re-loads as Time) — "!ruby/object:DateTime
|
|
92
|
+
# 2017-04-13 12:00:00.500000000 +09:00", to_s text, one line
|
|
93
|
+
when ::DateTime
|
|
94
|
+
anchored_scalar(obj, text: obj.strftime("%F %H:%M:%S.%9N %:z"),
|
|
95
|
+
tag: "!ruby/object:DateTime")
|
|
96
|
+
when ::Date, ::Time then anchored_scalar(obj) # timestamp text, never ivars
|
|
74
97
|
when ::Hash then visit_hash(obj)
|
|
75
98
|
when ::Array then visit_array(obj)
|
|
76
99
|
when ::Struct then visit_struct(obj)
|
|
@@ -101,7 +124,7 @@ module Yeptris
|
|
|
101
124
|
if @refs[oid] < 2
|
|
102
125
|
return [:none, nil]
|
|
103
126
|
end
|
|
104
|
-
name =
|
|
127
|
+
name = (@counter += 1).to_s # stdlib: &1, *1
|
|
105
128
|
@names[oid] = name
|
|
106
129
|
[:new, name]
|
|
107
130
|
end
|
|
@@ -156,7 +179,7 @@ module Yeptris
|
|
|
156
179
|
# neutral surface alone was pinned)
|
|
157
180
|
::Yeptris::YAML::BulkBuilder.time_text(obj)
|
|
158
181
|
elsif obj.is_a?(::Date)
|
|
159
|
-
obj.iso8601 # canonical calendar form
|
|
182
|
+
obj.iso8601 # canonical calendar form
|
|
160
183
|
elsif obj.nil?
|
|
161
184
|
"" # libyaml's null rendering rides bare (issue #290)
|
|
162
185
|
elsif obj.is_a?(::Float)
|
|
@@ -165,7 +188,7 @@ module Yeptris
|
|
|
165
188
|
obj.to_s
|
|
166
189
|
end
|
|
167
190
|
n =
|
|
168
|
-
if obj.is_a?(::String)
|
|
191
|
+
if obj.is_a?(::String) && !tag
|
|
169
192
|
::Yeptris::YAML::Builder.build_string(@tree, obj)
|
|
170
193
|
else
|
|
171
194
|
@tree.new_scalar(text, :plain)
|
|
@@ -220,7 +243,7 @@ module Yeptris
|
|
|
220
243
|
m = @tree.new_mapping
|
|
221
244
|
remember(strct, m)
|
|
222
245
|
m.set_anchor(name) if name
|
|
223
|
-
m.set_tag(strct.class.name ? "!ruby/struct
|
|
246
|
+
m.set_tag(strct.class.name.to_s.empty? ? "!ruby/struct" : "!ruby/struct:#{strct.class.name}")
|
|
224
247
|
strct.each_pair { |k, v| m.map_add(key_text(k), visit(v)) }
|
|
225
248
|
m
|
|
226
249
|
end
|
|
@@ -326,6 +349,9 @@ module Yeptris
|
|
|
326
349
|
when ::Yeptris::Psych::Nodes::Mapping then visit_mapping(node)
|
|
327
350
|
else node&.to_ruby
|
|
328
351
|
end
|
|
352
|
+
# stdlib register(): an anchored node's result is THE object
|
|
353
|
+
# for every alias to that anchor (scalars included)
|
|
354
|
+
anchors[node.anchor] = result if node.respond_to?(:anchor) && node.anchor
|
|
329
355
|
# the domain-types post-pass (stdlib ToRuby#accept's tail):
|
|
330
356
|
# registered blocks transform the revived result per node
|
|
331
357
|
if node && !::Yeptris::Psych.domain_types.empty?
|
data/lib/yeptris/psych.rb
CHANGED
|
@@ -299,10 +299,11 @@ module Yeptris
|
|
|
299
299
|
(0...doc.document_count).each do |i|
|
|
300
300
|
stream.children << Nodes::Builder.document_stream_child(doc, i)
|
|
301
301
|
end
|
|
302
|
+
# ownership: the DOCUMENT wrapper is the sole owner — its own
|
|
303
|
+
# finalizer (pointer-only closure) frees the C memory; the
|
|
304
|
+
# stream merely references it. A tree-side finalizer closing
|
|
305
|
+
# over the wrapper raced the wrapper's sweep (#182's abort).
|
|
302
306
|
stream.owner = doc
|
|
303
|
-
ObjectSpace.define_finalizer(
|
|
304
|
-
stream, proc { doc.free unless doc.freed? }
|
|
305
|
-
)
|
|
306
307
|
stream
|
|
307
308
|
rescue Yeptris::ParseError => e
|
|
308
309
|
raise SyntaxError.from_parse_error(e)
|
|
@@ -327,6 +328,11 @@ module Yeptris
|
|
|
327
328
|
# data anyway
|
|
328
329
|
out =
|
|
329
330
|
case obj
|
|
331
|
+
# DateTime < Date in ruby's hierarchy — the fast scalar
|
|
332
|
+
# path would emit it tag-less iso8601 (re-loading as Time);
|
|
333
|
+
# the visitor carries stdlib's !ruby/object:DateTime tag
|
|
334
|
+
when ::DateTime
|
|
335
|
+
Visitors::YAMLTree.new.push(obj).finish
|
|
330
336
|
when nil, true, false, ::String, ::Integer, ::Float, ::Symbol, ::Date, ::Time
|
|
331
337
|
Yeptris::YAML.dump(obj, header: true)
|
|
332
338
|
else
|
|
@@ -442,12 +448,13 @@ module Yeptris
|
|
|
442
448
|
@tags = tags
|
|
443
449
|
end
|
|
444
450
|
|
|
445
|
-
# @api private —
|
|
451
|
+
# @api private — attach the document: the tree REFERENCES it
|
|
452
|
+
# (keeping the C memory alive while the tree is reachable);
|
|
453
|
+
# the wrapper's own finalizer is the sole freer (#182: a
|
|
454
|
+
# tree-side finalizer closing over the wrapper raced the
|
|
455
|
+
# wrapper's sweep — SIGABRT under document churn)
|
|
446
456
|
def own(yeptris_doc)
|
|
447
457
|
@owner = yeptris_doc
|
|
448
|
-
ObjectSpace.define_finalizer(
|
|
449
|
-
self, proc { yeptris_doc.free unless yeptris_doc.freed? }
|
|
450
|
-
)
|
|
451
458
|
self
|
|
452
459
|
end
|
|
453
460
|
|
data/lib/yeptris.rb
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module Yeptris
|
|
4
4
|
# The gem's version lives in the parent namespace's file — the last
|
|
5
5
|
# internal require (yeptris/version) retired with it.
|
|
6
|
-
VERSION = "0.6.15.
|
|
6
|
+
VERSION = "0.6.15.2".freeze
|
|
7
7
|
# The error hierarchy lives in THIS file (the parent namespace's
|
|
8
8
|
# own file): nested constants do not trigger a parent-constant
|
|
9
9
|
# autoload, and the law forbids internal requires — defining the
|