leptris 1.9.311.1-arm-linux → 1.9.311.2-arm-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/CHANGELOG.md +17 -0
- data/ext/leptris/native/native.c +26 -2
- data/lib/leptris/version.rb +1 -1
- data/lib/leptris/xml/document.rb +12 -2
- data/lib/leptris/xml/native.so +0 -0
- 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: fc322e484037235b28d726c88ac8e036f5321bc17c95561c60ca90b3aa9b4d4a
|
|
4
|
+
data.tar.gz: 6388d7a7b8715785ac6bcdb734b82848c4e1683f72f5f81c7e6556fd255ba5da
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 486358f50f20bb8633919fab3159648e916efc984b5cc6813d641fb89c0cb463cab47e5c7c50dd5832ce6f993d28055901a2b1fe050d496c3a33531f8e54d9e9
|
|
7
|
+
data.tar.gz: ef13ab80d77dbae815f3cad97223a69a0574095df2def3b28ef1e846b538ad4bcf3c76dc70ccfc778690ccb0420f7fdbdc3fdc712bae4a18d672cf5c378d7b83
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
## [1.9.311.2] - 2026-10-06
|
|
2
|
+
|
|
3
|
+
### Fixed
|
|
4
|
+
|
|
5
|
+
- **Absorbed sources alive at exit no longer double-free the pool
|
|
6
|
+
(#386)**: `Document#absorb`'s handle-only contract was enforced
|
|
7
|
+
only by the explicit `#free` — the C lifetime handle's dfree
|
|
8
|
+
and the no-native Ruby finalizer still called
|
|
9
|
+
`leptris_document_free`, destroying a pool already owned (and
|
|
10
|
+
released) by the absorber. Libraries that pin adopted-source
|
|
11
|
+
documents (moxml's lifetime pins) aborted at exit-time
|
|
12
|
+
finalization (`leptris_pool_destroy` → `free_small_botch`). The
|
|
13
|
+
absorbed flag now lives where every release path reads it: the
|
|
14
|
+
shared `Freed` struct (Ruby finalizer) and the C handle
|
|
15
|
+
(`doc_handle_mark_absorbed`; dfree is handle-only when the pool
|
|
16
|
+
moved). Both paths pinned by subprocess regression specs.
|
|
17
|
+
|
|
1
18
|
## [1.9.311.1] - 2026-10-06
|
|
2
19
|
|
|
3
20
|
### Fixed
|
data/ext/leptris/native/native.c
CHANGED
|
@@ -2682,15 +2682,21 @@ static VALUE nf_fast_inner_xml(VALUE self, VALUE addr)
|
|
|
2682
2682
|
* Ruby-finalizer path (which stays for LEPTRIS_NO_NATIVE). */
|
|
2683
2683
|
struct doc_handle {
|
|
2684
2684
|
void *doc;
|
|
2685
|
+
/* Pool ownership transferred to an absorber (engine #1548):
|
|
2686
|
+
* the destination's free performs the real release, so this
|
|
2687
|
+
* handle's dfree is HANDLE-ONLY (#386: malloc_zone_error /
|
|
2688
|
+
* free_small_botch when an absorbed source survived to
|
|
2689
|
+
* exit-time finalization after its destination's release). */
|
|
2690
|
+
int absorbed;
|
|
2685
2691
|
};
|
|
2686
2692
|
|
|
2687
2693
|
static void dh_free(void *p)
|
|
2688
2694
|
{
|
|
2689
2695
|
struct doc_handle *h = p;
|
|
2690
|
-
if (h->doc) {
|
|
2696
|
+
if (h->doc && !h->absorbed) {
|
|
2691
2697
|
f_doc_free(h->doc);
|
|
2692
|
-
h->doc = NULL;
|
|
2693
2698
|
}
|
|
2699
|
+
h->doc = NULL;
|
|
2694
2700
|
}
|
|
2695
2701
|
|
|
2696
2702
|
static size_t dh_size(const void *p)
|
|
@@ -2888,6 +2894,22 @@ static VALUE nf_doc_handle_release(VALUE self, VALUE document)
|
|
|
2888
2894
|
return Qnil;
|
|
2889
2895
|
}
|
|
2890
2896
|
|
|
2897
|
+
/* Absorption bookkeeping (#386, engine #1548): Document#absorb
|
|
2898
|
+
* calls this on the SOURCE right after the engine transfers pool
|
|
2899
|
+
* ownership — the handle's dfree becomes handle-only, matching
|
|
2900
|
+
* the Ruby-side Freed flag the no-native finalizer reads. */
|
|
2901
|
+
static VALUE nf_doc_handle_mark_absorbed(VALUE self, VALUE document)
|
|
2902
|
+
{
|
|
2903
|
+
VALUE handle = rb_ivar_get(document, id_iv_doc_handle);
|
|
2904
|
+
(void)self;
|
|
2905
|
+
if (handle != Qnil) {
|
|
2906
|
+
struct doc_handle *h;
|
|
2907
|
+
TypedData_Get_Struct(handle, struct doc_handle, &dh_type, h);
|
|
2908
|
+
h->absorbed = 1;
|
|
2909
|
+
}
|
|
2910
|
+
return Qnil;
|
|
2911
|
+
}
|
|
2912
|
+
|
|
2891
2913
|
/* The full Document.create in one dispatch: engine create,
|
|
2892
2914
|
* binding wrapper (ivar-seeded, bypassing initialize), and the
|
|
2893
2915
|
* lifetime handle. Returns Qnil when the engine refuses. */
|
|
@@ -3158,6 +3180,8 @@ LEPTRIS_INIT_EXPORT void Init_native(void)
|
|
|
3158
3180
|
nf_doc_handle_attach, 1);
|
|
3159
3181
|
rb_define_module_function(m_native, "doc_handle_release",
|
|
3160
3182
|
nf_doc_handle_release, 1);
|
|
3183
|
+
rb_define_module_function(m_native, "doc_handle_mark_absorbed",
|
|
3184
|
+
nf_doc_handle_mark_absorbed, 1);
|
|
3161
3185
|
rb_define_module_function(m_native, "create_binding_document",
|
|
3162
3186
|
nf_create_binding_document, 0);
|
|
3163
3187
|
c_doc_handle = rb_define_class_under(m_xml, "DocHandle", rb_cObject);
|
data/lib/leptris/version.rb
CHANGED
data/lib/leptris/xml/document.rb
CHANGED
|
@@ -11,7 +11,9 @@ class Leptris::XML::Document
|
|
|
11
11
|
# the explicit `free` path and the finalizer. This eliminates the
|
|
12
12
|
# double-free that FFI::AutoPointer's release proc caused when
|
|
13
13
|
# `Document#free` was called explicitly and then GC ran.
|
|
14
|
-
|
|
14
|
+
# +absorbed+ (engine #1548, #386): pool ownership moved to an
|
|
15
|
+
# absorber — the finalizer must never call the engine free.
|
|
16
|
+
Freed = Struct.new(:state, :absorbed) # state: :alive | :freed
|
|
15
17
|
|
|
16
18
|
# Mutation version: advanced by every data mutation (via
|
|
17
19
|
# Node#ensure_writable!, root=, add_pi). Node memos stamp the
|
|
@@ -286,7 +288,7 @@ class Leptris::XML::Document
|
|
|
286
288
|
|
|
287
289
|
def self.finalizer(address, freed)
|
|
288
290
|
proc do
|
|
289
|
-
next if freed.state == :freed
|
|
291
|
+
next if freed.state == :freed || freed.absorbed
|
|
290
292
|
freed.state = :freed
|
|
291
293
|
Leptris::XML::FFI.leptris_document_free(::FFI::Pointer.new(address))
|
|
292
294
|
end
|
|
@@ -591,8 +593,16 @@ class Leptris::XML::Document
|
|
|
591
593
|
# objects by hand): the absorbed document's #free skips the
|
|
592
594
|
# engine release, and splice seams skip source-side removals
|
|
593
595
|
# because absorbed splices MOVE the node (nothing to remove).
|
|
596
|
+
# The flag is mirrored into every release path (#386): the
|
|
597
|
+
# shared Freed struct (the no-native Ruby finalizer reads it)
|
|
598
|
+
# and the C lifetime handle (dh_free must be handle-only when
|
|
599
|
+
# the pool belongs to the absorber).
|
|
594
600
|
def mark_absorbed_into(destination)
|
|
595
601
|
@absorbed_into = destination
|
|
602
|
+
@freed.absorbed = true
|
|
603
|
+
if defined?(Leptris::XML::NATIVE_FAST)
|
|
604
|
+
Leptris::XML::Native.doc_handle_mark_absorbed(self)
|
|
605
|
+
end
|
|
596
606
|
end
|
|
597
607
|
|
|
598
608
|
def absorbed_into?(destination)
|
data/lib/leptris/xml/native.so
CHANGED
|
Binary file
|