leptris 1.9.40 → 1.9.42
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/CHANGELOG.md +31 -0
- data/lib/leptris/version.rb +1 -1
- data/lib/leptris/xml/ffi.rb +12 -5
- data/lib/leptris/xml/pull.rb +19 -5
- 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: 5de687a1b7597e0bdf6ff80f85566435d9927e136a86ec758a554928d85910d2
|
|
4
|
+
data.tar.gz: 9171a19d4620e4d482c573e1f21e76a8ee253b175a8df34569e9711f1fcc42e4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b2dadeb0a139c9a6396dd82defd080dc014e056a8959321a7f7dff13851503d8d53b6a7b1dc4f987a4bb131ce9054e3c0073d7234d6a8ff0e73caae2fc71cf7e
|
|
7
|
+
data.tar.gz: 1648229492701f2805e405475b7abf4f59108844d79da56118f47e15fdb048ebf03f5b7a1d4c3f48c566e2c13b1881b50b7a09df9512fcb2cd928ae045260f3a
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,37 @@ All notable changes to Leptris will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.9.42] - 2026-08-30
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- **Pull batch staging corruption: fail loudly, never deliver
|
|
13
|
+
garbage (leptris/leptris#646)**: `leptris_pull_next_batch`'s
|
|
14
|
+
staging arena misplaces record strings once staged content
|
|
15
|
+
crosses its block boundary (~185 bytes of attribute value under
|
|
16
|
+
nested attr-carrying ancestors — the #625 fix family did not
|
|
17
|
+
reach the batch staging). `Parser#each_batch` now validates each
|
|
18
|
+
staged record — unknown type codes, empty/control-byte/invalid-
|
|
19
|
+
encoding names cannot be legal XML events — and raises a
|
|
20
|
+
descriptive error pointing at `#each` (the cursor path reads the
|
|
21
|
+
same documents correctly; SAX default, recorder drain, and DOM
|
|
22
|
+
are unaffected). Bisection attached upstream: ok at 180 staged
|
|
23
|
+
bytes, corrupt at 190, in the minimized shape.
|
|
24
|
+
|
|
25
|
+
## [1.9.41] - 2026-08-30
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
|
|
29
|
+
- **One thread-local access per children batch**: fetch_children
|
|
30
|
+
re-looked up the scratch hash inside the ints helper on every
|
|
31
|
+
call; both buffers now resolve through a single access (and the
|
|
32
|
+
kinds buffer sizes from the pointers capacity directly). Cold
|
|
33
|
+
full-tree walk: 254 -> 247 ms per big.xml walk (the gap vs
|
|
34
|
+
Nokogiri narrows 1.66x -> 1.56x — the remainder is the binding's
|
|
35
|
+
per-node allocation floor, re-measured and filed upstream as
|
|
36
|
+
leptris/leptris#645 together with the unchanged 1.64x scalar
|
|
37
|
+
XPath gap from #617's other half).
|
|
38
|
+
|
|
8
39
|
## [1.9.40] - 2026-08-30
|
|
9
40
|
|
|
10
41
|
### Changed
|
data/lib/leptris/version.rb
CHANGED
data/lib/leptris/xml/ffi.rb
CHANGED
|
@@ -911,17 +911,22 @@ module Leptris
|
|
|
911
911
|
# (leptris_node_children_ex, 1.9.18 #617) so wrappers skip
|
|
912
912
|
# the per-child get_type dispatch.
|
|
913
913
|
def self.fetch_children(c_ptr)
|
|
914
|
+
# One thread-local access serves both buffers (the helper
|
|
915
|
+
# re-looked it up); the kinds buffer sizes from the POINTERS
|
|
916
|
+
# buffer's capacity — it may have grown past FETCH_INITIAL on
|
|
917
|
+
# earlier use, and C writes one kind per copied child.
|
|
914
918
|
scratch = (Thread.current[:leptris_scratch] ||= {})
|
|
915
919
|
buffer = scratch[:pointers]
|
|
916
920
|
if buffer.nil?
|
|
917
921
|
buffer = scratch[:pointers] =
|
|
918
922
|
::FFI::MemoryPointer.new(:pointer, FETCH_INITIAL)
|
|
919
923
|
end
|
|
920
|
-
# size the kinds buffer from the POINTERS buffer's capacity —
|
|
921
|
-
# it may have grown past FETCH_INITIAL on earlier use, and C
|
|
922
|
-
# writes one kind per copied child
|
|
923
924
|
cap = buffer.size / PTR_BYTES
|
|
924
|
-
kinds =
|
|
925
|
+
kinds = scratch[:ints]
|
|
926
|
+
if kinds.nil? || kinds.size / INT_BYTES < cap
|
|
927
|
+
kinds&.free
|
|
928
|
+
kinds = scratch[:ints] = ::FFI::MemoryPointer.new(:int, cap)
|
|
929
|
+
end
|
|
925
930
|
copied = leptris_node_children_ex(c_ptr, buffer, kinds, cap)
|
|
926
931
|
if copied == cap
|
|
927
932
|
total = leptris_node_children_ex(c_ptr, nil, nil, 0)
|
|
@@ -929,7 +934,9 @@ module Leptris
|
|
|
929
934
|
buffer.free
|
|
930
935
|
buffer = scratch[:pointers] =
|
|
931
936
|
::FFI::MemoryPointer.new(:pointer, total)
|
|
932
|
-
kinds
|
|
937
|
+
kinds.free
|
|
938
|
+
kinds = scratch[:ints] =
|
|
939
|
+
::FFI::MemoryPointer.new(:int, total)
|
|
933
940
|
copied = leptris_node_children_ex(c_ptr, buffer, kinds, total)
|
|
934
941
|
end
|
|
935
942
|
end
|
data/lib/leptris/xml/pull.rb
CHANGED
|
@@ -85,14 +85,28 @@ module Leptris::XML::Pull
|
|
|
85
85
|
name_ptr = buffer.get_pointer(base + name_off)
|
|
86
86
|
text_ptr = buffer.get_pointer(base + text_off)
|
|
87
87
|
type = TYPES[buffer.get_int(base + type_off)]
|
|
88
|
+
name = name_ptr.null? ? nil :
|
|
89
|
+
name_ptr.read_string.force_encoding(Encoding::UTF_8)
|
|
90
|
+
# Staging-corruption guard (leptris/leptris#646): the C
|
|
91
|
+
# batch's staging arena misplaces record strings once the
|
|
92
|
+
# staged content crosses its block boundary (~185 bytes of
|
|
93
|
+
# attribute value under nested attr-carrying ancestors) —
|
|
94
|
+
# names come back empty, control-byte-laced, or
|
|
95
|
+
# invalid-encoding, and unknown type codes surface as nil.
|
|
96
|
+
# Element names can never look like that: fail loudly
|
|
97
|
+
# instead of delivering garbage, and point at the cursor
|
|
98
|
+
# path, which reads the same documents correctly.
|
|
99
|
+
if type.nil? ||
|
|
100
|
+
(name && (name.empty? || !name.valid_encoding? ||
|
|
101
|
+
name.match?(/[\x00-\x08\x0e-\x1f]/)))
|
|
102
|
+
raise Leptris::XML::Error,
|
|
103
|
+
"pull batch staging corruption (leptris/leptris#646) — " \
|
|
104
|
+
"use Parser#each (cursor) for this document"
|
|
105
|
+
end
|
|
88
106
|
text = text_ptr.null? ? nil :
|
|
89
107
|
text_ptr.read_string.force_encoding(Encoding::UTF_8)
|
|
90
108
|
text = Leptris::XML::FFI.read_pi_data(text) if type == :pi
|
|
91
|
-
Event.new(type,
|
|
92
|
-
name_ptr.null? ? nil :
|
|
93
|
-
name_ptr.read_string.force_encoding(Encoding::UTF_8),
|
|
94
|
-
text, nil
|
|
95
|
-
)
|
|
109
|
+
Event.new(type, name, text, nil)
|
|
96
110
|
end
|
|
97
111
|
# The attr mirror holds the batch's most recent start.
|
|
98
112
|
last_start = nil
|