leptris 1.9.365.1 → 1.9.366.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: 973845563957861b68366fd3c90f3a8d3f1a5ba5921e09f2a2dc268542faa8b6
4
- data.tar.gz: 71814d603d2c40586dc2e3c3aa9d36750e67a8cdb54864257a9f56cfa076a6c8
3
+ metadata.gz: 97ab0ffc1ab21b11d43593a97f8d91f75f49028460d68d5f0fdf7dbe14f697f7
4
+ data.tar.gz: 3badee92d7d7744c93da9434badb3401e7b4e5b4f61acc3e984029ed16dcf903
5
5
  SHA512:
6
- metadata.gz: f298b9d5e3ac0ffd299ee2323b4efcadddd2c7c7f09be765009c3764d99bbfeb88e3720a92888fbfda3195dfa5bededeca05e38c1790c7c2071fd87807718ed8
7
- data.tar.gz: ea9086febdac6a55cb745ce9c240ed7ea2db9ac26843b6b1bfcca43c873a9fbcce1f522dff609ef83a8c62e9af98120d6e9dad18649ba0ec3ea77556c215d0cd
6
+ metadata.gz: 9222fe57cebd087fe04c892116bd771266c1671039d2c8a6bf7fd0846b746210766adc8db5c7824289e9cd7e48cb17effb3ec37a2505732f29da52068ccf7fe9
7
+ data.tar.gz: 6f9fc5fc3e204d9112e9f49bdd829b3a0c11360135a8037f471753c01e414e688a6b94ee35f2bf89113898d0f702119f1f076e4716dac17fa2da9077bbbdd4b5
data/Rakefile CHANGED
@@ -8,7 +8,7 @@ RSpec::Core::RakeTask.new(:spec)
8
8
  # Pin for `rake compile` and the platform-gem builds. Keep in lockstep
9
9
  # with .github/workflows/build.yml (which calls `rake compile`) and the
10
10
  # CHANGELOG when libleptris releases.
11
- LIBLEPTRIS_VERSION = "1.9.365"
11
+ LIBLEPTRIS_VERSION = "1.9.366"
12
12
  # Vendored alongside libleptris for fn:normalize-unicode (TODO
13
13
  # .restructure/20): built per platform with a RELOCATABLE @rpath
14
14
  # install name, loaded by ffi.rb before libleptris so the
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Leptris
4
- VERSION = "1.9.365.1"
4
+ VERSION = "1.9.366.1"
5
5
  end
data/vendor-src/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  Sources vendored in this gem (recompile rights; the ruby
2
2
  variant builds them at install via extconf.rb):
3
3
 
4
- - libleptris v1.9.365
4
+ - libleptris v1.9.366
5
5
  - utf8proc v2.11.0
6
6
 
7
7
  Rebuild by hand:
@@ -1,5 +1,27 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.9.366] - 2026-10-17
4
+
5
+ ### Fixed
6
+
7
+ - **dom: the foreign leaf adopt copies exactly the argument node (#1755, PR #1757).**
8
+ `adopt_for_splice`'s non-element branch ran a wholesale sibling-chain copy
9
+ (`copy_leaf_chain`) whose switch had no ELEMENT case: any mixed-content
10
+ chain — a text node whose next sibling is the element that follows it, the
11
+ standard fragment shape lutaml/moxml produce — hit `default:` and the whole
12
+ append failed with `LEPTRIS_ERROR_MEMORY` ("Memory allocation failed": a
13
+ lie; nothing was out of memory). The run-copy was also wrong for every
14
+ caller that reaches this path — the binding's fragment loop and moxml's
15
+ NodeSet iteration append fragment children individually, so a chain copy
16
+ duplicated every later sibling even where it succeeded. The foreign leaf
17
+ adopt now copies exactly the argument (doc-level leaves were already
18
+ single-node for the same reason, #1539); the single-caller chain copier is
19
+ deleted. This is the deterministic face of the Ruby 4.0 render crash
20
+ (leptris-ruby#489): the GC-stressed metanorma collection render goes
21
+ 2 failures -> 0. Engine suite 2048/2048; binding suite 1094/1094.
22
+
23
+
24
+
3
25
  ## [1.9.365] - 2026-10-16
4
26
 
5
27
  ### Fixed
@@ -3,7 +3,7 @@
3
3
  cmake_minimum_required(VERSION 3.20)
4
4
 
5
5
  project(leptris
6
- VERSION 1.9.365
6
+ VERSION 1.9.366
7
7
  DESCRIPTION "Fast XML parser and XPath evaluator in pure C"
8
8
  LANGUAGES C CXX
9
9
  )
@@ -359,74 +359,6 @@ static LeptrisNode* copy_leaf_one(LeptrisNode* c,
359
359
  }
360
360
  }
361
361
 
362
- /* #1534: copy a non-element node (plus its linked tail — the #540
363
- * chain shape) into the target document's pool. Same per-kind
364
- * creation helpers the subtree copier uses. */
365
- static LeptrisNode* copy_leaf_chain(LeptrisNode* head,
366
- struct leptris_document* target) {
367
- LeptrisNode* copy_head = NULL;
368
- LeptrisNode* copy_tail = NULL;
369
- for (LeptrisNode* c = head; c;
370
- c = leptris_node_get_next_sibling(c)) {
371
- LeptrisNode* cc = NULL;
372
- switch (c->type) {
373
- case LEPTRIS_NODE_TYPE_TEXT: {
374
- LeptrisTextNode* t = (LeptrisTextNode*)c;
375
- const char* content = leptris_textnode_content(t);
376
- cc = (LeptrisNode*)leptris_text_create(
377
- content, t->content_len, target->pool, target);
378
- break;
379
- }
380
- case LEPTRIS_NODE_TYPE_CDATA: {
381
- LeptrisCDATANode* cd = (LeptrisCDATANode*)c;
382
- cc = (LeptrisNode*)leptris_cdata_create(
383
- cd->content, cd->content ? strlen(cd->content) : 0,
384
- target->pool);
385
- break;
386
- }
387
- case LEPTRIS_NODE_TYPE_COMMENT: {
388
- LeptrisCommentNode* cm = (LeptrisCommentNode*)c;
389
- cc = (LeptrisNode*)leptris_comment_create(
390
- cm->content,
391
- cm->content ? strlen(cm->content) : 0,
392
- target->pool);
393
- break;
394
- }
395
- case LEPTRIS_NODE_TYPE_PI: {
396
- LeptrisPINode* pi = (LeptrisPINode*)c;
397
- cc = (LeptrisNode*)leptris_pi_create(
398
- pi->target, pi->target ? strlen(pi->target) : 0,
399
- pi->data ? pi->data : "",
400
- pi->data ? strlen(pi->data) : 0, target->pool);
401
- break;
402
- }
403
- case LEPTRIS_NODE_TYPE_ENTITY_REF: {
404
- LeptrisEntityRefNode* er = (LeptrisEntityRefNode*)c;
405
- cc = (LeptrisNode*)leptris_entity_ref_create(
406
- er->name, er->name ? strlen(er->name) : 0,
407
- target->pool);
408
- break;
409
- }
410
- default:
411
- cc = NULL;
412
- }
413
- if (!cc) {
414
- /* OOM mid-chain: copies already made live only in the
415
- * target pool — no caller-visible handle exists, and
416
- * document free reclaims them (the same conservatism
417
- * copy_subtree_detached uses on !cc). */
418
- return NULL;
419
- }
420
- if (!copy_head) {
421
- copy_head = cc;
422
- } else {
423
- leptris_node_set_next_sibling(copy_tail, cc);
424
- }
425
- copy_tail = cc;
426
- }
427
- return copy_head;
428
- }
429
-
430
362
  static LeptrisNode* adopt_for_splice(LeptrisNode* node,
431
363
  struct leptris_document* target) {
432
364
  if (!node || !target) return node;
@@ -465,13 +397,15 @@ static LeptrisNode* adopt_for_splice(LeptrisNode* node,
465
397
  * the target — its pool dies with the target, so the node
466
398
  * moves by reference. */
467
399
  if (src->absorbed_by == target) return node;
468
- /* top == node: a DOC-LEVEL leaf (prolog/epilog, #580) —
469
- * its sibling chain spans unrelated nodes (including the
470
- * root element), so copy exactly the argument (#1539).
471
- * An in-element leaf keeps the #540 chain shape. */
472
- if (top == node) return copy_leaf_one(node, target);
473
- LeptrisNode* copy = copy_leaf_chain(node, target);
474
- return copy;
400
+ /* Copy exactly the argument (#1755): the callers of this
401
+ * face append fragment children INDIVIDUALLY (the binding's
402
+ * fragment loop, moxml's NodeSet iteration), so a wholesale
403
+ * run copy duplicated every later sibling — and its missing
404
+ * ELEMENT case failed the whole append with
405
+ * LEPTRIS_ERROR_MEMORY on the first mixed-content chain.
406
+ * Doc-level leaves (prolog/epilog, #580) were already
407
+ * single-node for the same reason (#1539). */
408
+ return copy_leaf_one(node, target);
475
409
  }
476
410
  /* Type-safe walk to the chain top: get_document reads
477
411
  * element-form fields and misreads non-element structs. */
@@ -3019,6 +3019,58 @@ TEST(DomAttachInstalled, ForeignAttachReportsCopyAddress) {
3019
3019
  leptris_document_free(target);
3020
3020
  }
3021
3021
 
3022
+ /* leptris#1755: a foreign MIXED-CONTENT fragment hands the
3023
+ * engine a text node whose sibling chain carries the following
3024
+ * element. The leaf adopt ran a WHOLESALE chain copy that had no
3025
+ * ELEMENT case — the element hit default: and the whole append
3026
+ * failed with LEPTRIS_ERROR_MEMORY ("Memory allocation failed" —
3027
+ * a lie; nothing was out of memory). Every caller of this face
3028
+ * appends fragment children INDIVIDUALLY (the binding's fragment
3029
+ * loop, moxml's NodeSet iteration), so the foreign leaf adopt
3030
+ * copies exactly the argument node — the sibling run stays in the
3031
+ * source for its own appends. */
3032
+ TEST(DomAttachInstalled, ForeignMixedChainTextBeforeElement) {
3033
+ LeptrisStatus st = LEPTRIS_OK;
3034
+ const char* src = "<f>lead<item>t</item>tail</f>";
3035
+ LeptrisDocument frag = leptris_parse_string(src, strlen(src), &st);
3036
+ ASSERT_NE(frag, nullptr);
3037
+ LeptrisDocument target = leptris_parse_string("<doc/>", 6, &st);
3038
+ ASSERT_NE(target, nullptr);
3039
+ LeptrisElement troot = leptris_document_root(target);
3040
+ LeptrisElement froot = leptris_document_root(frag);
3041
+ /* node-level first child: the TEXT "lead" (the element-level
3042
+ * face would skip it and return <item>). */
3043
+ LeptrisNodeRef text = leptris_node_first_child((LeptrisNodeRef)froot);
3044
+ ASSERT_NE(text, nullptr);
3045
+ ASSERT_EQ(leptris_node_get_type(text), LEPTRIS_NODE_TYPE_TEXT);
3046
+
3047
+ EXPECT_EQ(leptris_element_add_child_addr(
3048
+ (uintptr_t)troot, (uintptr_t)text),
3049
+ LEPTRIS_OK);
3050
+ /* exactly the argument: no sibling run rides along (serialize
3051
+ * pins the child set; child_count is element-oriented) */
3052
+ char* out = leptris_element_serialize(troot, nullptr);
3053
+ ASSERT_NE(out, nullptr);
3054
+ EXPECT_STREQ(out, "<doc>lead</doc>");
3055
+ leptris_free_string(out);
3056
+
3057
+ /* the binding's loop continues: the element sibling appends on
3058
+ * its own, and the trailing text with it — no duplication of
3059
+ * the element the first adopt must NOT have carried */
3060
+ LeptrisElement item = leptris_element_first_child_any(froot);
3061
+ ASSERT_NE(item, nullptr);
3062
+ EXPECT_EQ(leptris_element_add_child_addr(
3063
+ (uintptr_t)troot, (uintptr_t)item),
3064
+ LEPTRIS_OK);
3065
+ /* the source dies; the installed copies must survive */
3066
+ leptris_document_free(frag);
3067
+ out = leptris_element_serialize(troot, nullptr);
3068
+ ASSERT_NE(out, nullptr);
3069
+ EXPECT_STREQ(out, "<doc>lead<item>t</item></doc>");
3070
+ leptris_free_string(out);
3071
+ leptris_document_free(target);
3072
+ }
3073
+
3022
3074
  TEST(DomAttachInstalled, SameDocumentReturnsArgument) {
3023
3075
  LeptrisStatus st = LEPTRIS_OK;
3024
3076
  LeptrisDocument d = leptris_parse_string("<r/>", 4, &st);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json",
3
3
  "name": "leptris",
4
- "version": "1.9.365",
4
+ "version": "1.9.366",
5
5
  "description": "High-performance XML parser and XPath 1.0 engine in C (libleptris)",
6
6
  "homepage": "https://github.com/leptris/leptris",
7
7
  "license": "MIT",
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: leptris
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.365.1
4
+ version: 1.9.366.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-10-16 00:00:00.000000000 Z
11
+ date: 2026-10-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi