Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

XSLT segfault #2800

Closed
Roguelazer opened this issue Feb 28, 2023 · 8 comments · Fixed by #2829
Closed

XSLT segfault #2800

Roguelazer opened this issue Feb 28, 2023 · 8 comments · Fixed by #2829
Labels
topic/memory Segfaults, memory leaks, valgrind testing, etc.
Milestone

Comments

@Roguelazer
Copy link

Please describe the bug

I've found a reproducible XSLT-related crash; it happens in both macOS and Linux and with both Ruby 3.1 and 3.2, but is rather much easier to trigger on macOS (not sure why). I have not been able to reproduce it with my minimal reproducer below on Ruby 2.7, but my full (much larger) application also crashes on Ruby 2.7, so I think it's broken there, too.

It can be fixed by duping the document passed to XSLT#transform, or by disabling garbage-collection process-wide.

Reproduction Script

require "nokogiri"

INPUT = <<~EOX
  <?xml version="1.0" encoding="UTF-8"?>
  <ReturnData>
    <Keys>
      <Key>Value</Key>
      <Key>Value</Key>
    </Keys>
  </ReturnData>
EOX

STYLESHEET = <<~EOX
  <?xml version="1.0" encoding="UTF-8"?>
  <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:strip-space elements="*"/>
  </xsl:stylesheet>
EOX

def munge_xml(doc)
  new = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml|
    xml.AppData {
      xml.Copied {}
    }
  end.doc
  copied = new.at("//Copied")
  doc.at("//ReturnData").children.each do |child|
    copied.add_child(child.dup(1, new))
  end
  new
end

def main
  30.times do
    doc = Nokogiri::XML(INPUT)
    munge_xml(doc)
    stylesheet = Nokogiri::XSLT STYLESHEET
    if ARGV[0] == "dup"
      puts stylesheet.transform(doc.dup).to_s.size
    else
      puts stylesheet.transform(doc).to_s.size
    end
  end
end

main

Run this as "ruby script.rb" and it should crash (most of the time; it depends on exactly what the GC feels like doing), run it as "ruby script.rb dup" and it does not crash ever.

Backtrace

/Users/james/pg/efile-viewer-2/.bundle/ruby/3.2.0/gems/nokogiri-1.14.2-arm64-darwin/lib/nokogiri/xml/node.rb:1363: [BUG] Segmentation fault at 0x0000000000000000
ruby 3.2.1 (2023-02-08 revision 31819e82c8) [arm64-darwin22]

-- Crash Report log information --------------------------------------------
   See Crash Report log file in one of the following locations:
     * ~/Library/Logs/DiagnosticReports
     * /Library/Logs/DiagnosticReports
   for more details.
Don't forget to include the above Crash Report log file in bug reports.

-- Control frame information -----------------------------------------------
c:0008 p:---- s:0056 e:000055 CFUNC  :*
c:0007 p:0142 s:0051 e:000050 METHOD /Users/james/pg/efile-viewer-2/.bundle/ruby/3.2.0/gems/nokogiri-1.14.2-arm64-darwin/lib/nokogiri/xml/node.rb:1363
c:0006 p:0019 s:0039 e:000038 METHOD /Users/james/pg/efile-viewer-2/.bundle/ruby/3.2.0/gems/nokogiri-1.14.2-arm64-darwin/lib/nokogiri/html5/node.rb:37
c:0005 p:0099 s:0026 e:000025 METHOD /Users/james/pg/efile-viewer-2/.bundle/ruby/3.2.0/gems/nokogiri-1.14.2-arm64-darwin/lib/nokogiri/xml/node.rb:1295
c:0004 p:0010 s:0017 e:000016 METHOD /Users/james/pg/efile-viewer-2/.bundle/ruby/3.2.0/gems/nokogiri-1.14.2-arm64-darwin/lib/nokogiri/xml/node.rb:1191
c:0003 p:0058 s:0013 e:000011 METHOD repro.rb:40
c:0002 p:0027 s:0006 e:000005 EVAL   repro.rb:44 [FINISH]
c:0001 p:0000 s:0003 E:000210 DUMMY  [FINISH]

-- Ruby level backtrace information ----------------------------------------
repro.rb:44:in `<main>'
repro.rb:40:in `main'
/Users/james/pg/efile-viewer-2/.bundle/ruby/3.2.0/gems/nokogiri-1.14.2-arm64-darwin/lib/nokogiri/xml/node.rb:1191:in `to_s'
/Users/james/pg/efile-viewer-2/.bundle/ruby/3.2.0/gems/nokogiri-1.14.2-arm64-darwin/lib/nokogiri/xml/node.rb:1295:in `serialize'
/Users/james/pg/efile-viewer-2/.bundle/ruby/3.2.0/gems/nokogiri-1.14.2-arm64-darwin/lib/nokogiri/html5/node.rb:37:in `write_to'
/Users/james/pg/efile-viewer-2/.bundle/ruby/3.2.0/gems/nokogiri-1.14.2-arm64-darwin/lib/nokogiri/xml/node.rb:1363:in `write_to'
/Users/james/pg/efile-viewer-2/.bundle/ruby/3.2.0/gems/nokogiri-1.14.2-arm64-darwin/lib/nokogiri/xml/node.rb:1363:in `*'

-- Machine register context ------------------------------------------------
  x0: 0x0000600003fe2880  x1: 0x000000010700ccd4  x2: 0x000000016d5ddab0
  x3: 0x0000000102f0e3a8  x4: 0x0000000000000000  x5: 0x0000000000001d40
  x6: 0x00006000013e9d40  x7: 0x0000000130008150 x18: 0x0000000000000000
 x19: 0x000000013d80b000 x20: 0x0000000105c6c8d8 x21: 0x0000000000000005
 x22: 0x000000013d80b388 x23: 0x0000000105c70410 x24: 0x000000016d5ddc10
 x25: 0x000000000000001a x26: 0x0000000000000000 x27: 0x0000000000000028
 x28: 0x000000013d80b388  lr: 0x0000000102f08038  fp: 0x000000016d5ddbe0
  sp: 0x000000016d5ddbb0

-- C level backtrace information -------------------------------------------
/opt/homebrew/Cellar/ruby/3.2.1/lib/libruby.3.2.dylib(rb_vm_bugreport+0x324) [0x103056d84]
/opt/homebrew/Cellar/ruby/3.2.1/lib/libruby.3.2.dylib(rb_bug_for_fatal_signal) [0x102ee8514]
/opt/homebrew/Cellar/ruby/3.2.1/lib/libruby.3.2.dylib(sig_do_nothing) [0x102fde430]
/usr/lib/system/libsystem_platform.dylib(_sigtramp+0x38) [0x1978442a4]
/opt/homebrew/Cellar/ruby/3.2.1/lib/libruby.3.2.dylib(gc_marks_rest) [0x102f08038]
/opt/homebrew/Cellar/ruby/3.2.1/lib/libruby.3.2.dylib(gc_start) [0x102f0cbd0]
/opt/homebrew/Cellar/ruby/3.2.1/lib/libruby.3.2.dylib(newobj_alloc) [0x102f0793c]
/opt/homebrew/Cellar/ruby/3.2.1/lib/libruby.3.2.dylib(rb_wb_protected_newobj_of) [0x102efc630]
/opt/homebrew/Cellar/ruby/3.2.1/lib/libruby.3.2.dylib(str_new0) [0x102fea4b8]
/opt/homebrew/Cellar/ruby/3.2.1/lib/libruby.3.2.dylib(rb_str_times) [0x102fed0a0]
/opt/homebrew/Cellar/ruby/3.2.1/lib/libruby.3.2.dylib(vm_call_cfunc_with_frame) [0x10304d090]
/opt/homebrew/Cellar/ruby/3.2.1/lib/libruby.3.2.dylib(vm_sendish) [0x10304ef4c]
/opt/homebrew/Cellar/ruby/3.2.1/lib/libruby.3.2.dylib(vm_exec_core) [0x103036534]
/opt/homebrew/Cellar/ruby/3.2.1/lib/libruby.3.2.dylib(rb_vm_exec) [0x103045710]
/opt/homebrew/Cellar/ruby/3.2.1/lib/libruby.3.2.dylib(rb_ec_exec_node) [0x102eef704]
/opt/homebrew/Cellar/ruby/3.2.1/lib/libruby.3.2.dylib(ruby_run_node) [0x102eef578]
/opt/homebrew/Cellar/ruby/3.2.1/bin/ruby(main+0x68) [0x102823f34]

Environment

# Nokogiri (1.14.2)
    ---
    warnings: []
    nokogiri:
      version: 1.14.2
      cppflags:
      - "-I/Users/james/pg/efile-viewer-2/.bundle/ruby/3.2.0/gems/nokogiri-1.14.2-arm64-darwin/ext/nokogiri"
      - "-I/Users/james/pg/efile-viewer-2/.bundle/ruby/3.2.0/gems/nokogiri-1.14.2-arm64-darwin/ext/nokogiri/include"
      - "-I/Users/james/pg/efile-viewer-2/.bundle/ruby/3.2.0/gems/nokogiri-1.14.2-arm64-darwin/ext/nokogiri/include/libxml2"
      ldflags: []
    ruby:
      version: 3.2.1
      platform: arm64-darwin22
      gem_platform: arm64-darwin-22
      description: ruby 3.2.1 (2023-02-08 revision 31819e82c8) [arm64-darwin22]
      engine: ruby
    libxml:
      source: packaged
      precompiled: true
      patches:
      - 0001-Remove-script-macro-support.patch
      - 0002-Update-entities-to-remove-handling-of-ssi.patch
      - 0003-libxml2.la-is-in-top_builddir.patch
      - '0009-allow-wildcard-namespaces.patch'
      libxml2_path: "/Users/james/pg/efile-viewer-2/.bundle/ruby/3.2.0/gems/nokogiri-1.14.2-arm64-darwin/ext/nokogiri"
      memory_management: ruby
      iconv_enabled: true
      compiled: 2.10.3
      loaded: 2.10.3
    libxslt:
      source: packaged
      precompiled: true
      patches:
      - 0001-update-automake-files-for-arm64.patch
      datetime_enabled: true
      compiled: 1.1.37
      loaded: 1.1.37
    other_libraries:
      zlib: 1.2.13
      libiconv: '1.17'
      libgumbo: 1.0.0-nokogiri
@Roguelazer Roguelazer added the state/needs-triage Inbox for non-installation-related bug reports or help requests label Feb 28, 2023
@flavorjones
Copy link
Member

@Roguelazer Thank you so much for reporting this! I'll take a look this week.

@flavorjones flavorjones added topic/memory Segfaults, memory leaks, valgrind testing, etc. and removed state/needs-triage Inbox for non-installation-related bug reports or help requests labels Mar 1, 2023
@flavorjones
Copy link
Member

Running this under valgrind shows the following memory access problem:

==542200== Invalid read of size 8
==542200==    at 0xCC901C4: _xml_node_mark (xml_node.c:17)
==542200==    by 0x49BF8A6: gc_mark_children (gc.c:7317)
==542200==    by 0x49C0E68: gc_mark_stacked_objects (gc.c:7437)
==542200==    by 0x49C0E68: gc_mark_stacked_objects_all (gc.c:7477)
==542200==    by 0x49C0E68: gc_marks_rest (gc.c:8675)
==542200==    by 0x49C1E48: gc_marks (gc.c:8716)
==542200==    by 0x49C1E48: gc_start (gc.c:9547)
==542200==    by 0x49C2A62: heap_prepare (gc.c:2431)
==542200==    by 0x49C2A62: heap_next_free_page (gc.c:2672)
==542200==    by 0x49C2A62: newobj_alloc (gc.c:2780)
==542200==    by 0x49C564E: newobj_of0 (gc.c:2876)
==542200==    by 0x49C564E: newobj_of (gc.c:2896)
==542200==    by 0x49C564E: rb_wb_protected_newobj_of (gc.c:2918)
==542200==    by 0x4B02E7F: str_alloc_embed (string.c:890)
==542200==    by 0x4B02E7F: str_new0 (string.c:926)
==542200==    by 0x4B08A8C: str_new_frozen_buffer (string.c:1461)
==542200==    by 0x49E835C: io_fwritev (io.c:2156)
==542200==    by 0x49E88EA: io_writev (io.c:2211)
==542200==    by 0x4B8E53E: vm_call0_cfunc_with_frame (vm_eval.c:150)
==542200==    by 0x4B8E53E: vm_call0_cfunc (vm_eval.c:164)
==542200==    by 0x4B8E53E: vm_call0_body (vm_eval.c:210)
==542200==    by 0x4B91B4B: vm_call0_cc (vm_eval.c:87)
==542200==    by 0x4B91B4B: rb_funcallv_scope (vm_eval.c:1051)
==542200==    by 0x4B91B4B: rb_funcallv (vm_eval.c:1066)
==542200==    by 0x49EC45E: rb_io_writev (io.c:2288)
==542200==    by 0x49EC45E: rb_io_puts (io.c:8925)
==542200==    by 0x49EC45E: rb_io_puts (io.c:8899)
==542200==    by 0x4B8E53E: vm_call0_cfunc_with_frame (vm_eval.c:150)
==542200==    by 0x4B8E53E: vm_call0_cfunc (vm_eval.c:164)
==542200==    by 0x4B8E53E: vm_call0_body (vm_eval.c:210)
==542200==    by 0x4B90B8E: vm_call0_cc (vm_eval.c:87)
==542200==    by 0x4B90B8E: rb_call0 (vm_eval.c:551)
==542200==    by 0x4B914C5: rb_call (vm_eval.c:877)
==542200==    by 0x4B914C5: rb_funcallv_kw (vm_eval.c:1074)
==542200==    by 0x4B702B7: vm_call_cfunc_with_frame (vm_insnhelper.c:3252)
==542200==    by 0x4B7FCBB: vm_sendish (vm_insnhelper.c:5064)
==542200==    by 0x4B7FCBB: vm_exec_core (insns.def:820)
==542200==    by 0x4B85726: rb_vm_exec (vm.c:2374)
==542200==    by 0x4B89FB6: invoke_block (vm.c:1398)
==542200==    by 0x4B89FB6: invoke_iseq_block_from_c (vm.c:1454)
==542200==    by 0x4B89FB6: invoke_block_from_c_bh (vm.c:1472)
==542200==    by 0x4B89FB6: vm_yield_with_cref (vm.c:1509)
==542200==    by 0x4B89FB6: vm_yield (vm.c:1517)
==542200==    by 0x4B89FB6: rb_yield_0 (vm_eval.c:1348)
==542200==    by 0x4B89FB6: rb_yield_1 (vm_eval.c:1354)
==542200==    by 0x4A3BBEB: int_dotimes (numeric.c:5697)
==542200==    by 0x4B702B7: vm_call_cfunc_with_frame (vm_insnhelper.c:3252)
==542200==    by 0x4B7FDCC: vm_sendish (vm_insnhelper.c:5064)
==542200==    by 0x4B7FDCC: vm_exec_core (insns.def:801)
==542200==    by 0x4B86104: rb_vm_exec (vm.c:2383)
==542200==    by 0x499966A: rb_ec_exec_node (eval.c:289)
==542200==    by 0x499FAE2: ruby_run_node (eval.c:330)
==542200==    by 0x109186: rb_main (main.c:38)
==542200==    by 0x109186: main (main.c:57)
==542200==  Address 0xaaf09b0 is 64 bytes inside a block of size 120 free'd
==542200==    at 0x483F0C3: free (vg_replace_malloc.c:872)
==542200==    by 0x49B8D34: objspace_xfree (gc.c:12515)
==542200==    by 0x49B8D34: objspace_xfree (gc.c:12446)
==542200==    by 0x49B8D34: ruby_sized_xfree (gc.c:12615)
==542200==    by 0x49B8D34: ruby_sized_xfree (gc.c:12612)
==542200==    by 0xCD94800: xsltApplyStripSpaces (transform.c:5668)
==542200==    by 0xCD95722: xsltApplyStylesheetInternal (transform.c:5962)
==542200==    by 0xCC99BAB: transform (xslt_stylesheet.c:264)
==542200==    by 0x4B702B7: vm_call_cfunc_with_frame (vm_insnhelper.c:3252)
==542200==    by 0x4B7FCBB: vm_sendish (vm_insnhelper.c:5064)
==542200==    by 0x4B7FCBB: vm_exec_core (insns.def:820)
==542200==    by 0x4B85726: rb_vm_exec (vm.c:2374)
==542200==    by 0x4B89FB6: invoke_block (vm.c:1398)
==542200==    by 0x4B89FB6: invoke_iseq_block_from_c (vm.c:1454)
==542200==    by 0x4B89FB6: invoke_block_from_c_bh (vm.c:1472)
==542200==    by 0x4B89FB6: vm_yield_with_cref (vm.c:1509)
==542200==    by 0x4B89FB6: vm_yield (vm.c:1517)
==542200==    by 0x4B89FB6: rb_yield_0 (vm_eval.c:1348)
==542200==    by 0x4B89FB6: rb_yield_1 (vm_eval.c:1354)
==542200==    by 0x4A3BBEB: int_dotimes (numeric.c:5697)
==542200==    by 0x4B702B7: vm_call_cfunc_with_frame (vm_insnhelper.c:3252)
==542200==    by 0x4B7FDCC: vm_sendish (vm_insnhelper.c:5064)
==542200==    by 0x4B7FDCC: vm_exec_core (insns.def:801)
==542200==    by 0x4B86104: rb_vm_exec (vm.c:2383)
==542200==    by 0x499966A: rb_ec_exec_node (eval.c:289)
==542200==    by 0x499FAE2: ruby_run_node (eval.c:330)
==542200==    by 0x109186: rb_main (main.c:38)
==542200==    by 0x109186: main (main.c:57)
==542200==  Block was alloc'd at
==542200==    at 0x483C855: malloc (vg_replace_malloc.c:381)
==542200==    by 0x49C62D9: objspace_xmalloc0 (gc.c:12295)
==542200==    by 0xCD69EB5: xmlSAX2TextNode (SAX2.c:1856)
==542200==    by 0xCD6ADEA: xmlSAX2Text (SAX2.c:2633)
==542200==    by 0xCCC30EF: xmlParseContentInternal (parser.c:9933)
==542200==    by 0xCCC3E8F: xmlParseElement (parser.c:9991)
==542200==    by 0xCCC6C51: xmlParseDocument (parser.c:10828)
==542200==    by 0xCCC7117: xmlDoRead (parser.c:15175)
==542200==    by 0xCC8E85D: read_memory (xml_document.c:331)
==542200==    by 0x4B702B7: vm_call_cfunc_with_frame (vm_insnhelper.c:3252)
==542200==    by 0x4B7FCBB: vm_sendish (vm_insnhelper.c:5064)
==542200==    by 0x4B7FCBB: vm_exec_core (insns.def:820)
==542200==    by 0x4B85726: rb_vm_exec (vm.c:2374)
==542200==    by 0x4B89FB6: invoke_block (vm.c:1398)
==542200==    by 0x4B89FB6: invoke_iseq_block_from_c (vm.c:1454)
==542200==    by 0x4B89FB6: invoke_block_from_c_bh (vm.c:1472)
==542200==    by 0x4B89FB6: vm_yield_with_cref (vm.c:1509)
==542200==    by 0x4B89FB6: vm_yield (vm.c:1517)
==542200==    by 0x4B89FB6: rb_yield_0 (vm_eval.c:1348)
==542200==    by 0x4B89FB6: rb_yield_1 (vm_eval.c:1354)
==542200==    by 0x4A3BBEB: int_dotimes (numeric.c:5697)
==542200==    by 0x4B702B7: vm_call_cfunc_with_frame (vm_insnhelper.c:3252)
==542200==    by 0x4B7FDCC: vm_sendish (vm_insnhelper.c:5064)
==542200==    by 0x4B7FDCC: vm_exec_core (insns.def:801)
==542200==    by 0x4B86104: rb_vm_exec (vm.c:2383)
==542200==    by 0x499966A: rb_ec_exec_node (eval.c:289)
==542200==    by 0x499FAE2: ruby_run_node (eval.c:330)
==542200==    by 0x109186: rb_main (main.c:38)
==542200==    by 0x109186: main (main.c:57)
==542200== 

So: consider this reproduced! ☑️

I'll dig in on root causes next.

@flavorjones
Copy link
Member

OK, I've got a handle on this. Here's a minimal repro:

#! /usr/bin/env ruby

require "bundler/inline"

gemfile do
  source "https://rubygems.org"
  gem "nokogiri", path: "."
end

require "nokogiri"

doc = Nokogiri::XML(<<XML)
  <root>  </root>
XML

stylesheet = Nokogiri::XSLT(<<~STYLE)
  <?xml version="1.0" encoding="UTF-8"?>
  <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:strip-space elements="*"/>
  </xsl:stylesheet>
STYLE

doc.xpath("//root/text()") # wrap a Ruby object around the whitespace text node

stylesheet.transform(doc)

GC.start

What happens is the following:

  1. We wrap a Ruby object (XML::Text) around the empty text node
  2. We run an XSLT transformation that is destructive -- libxslt's implementation of strip-spaces will free the memory associated with any whitespace-only strings (see this block from xsltApplyStripSpaces in transform.c).
  3. The XML::Text Ruby object still has a pointer to the original xmlNode C struct which has been freed.
  4. When the "mark" phase of GC kicks off, the XML::Text node is asked to mark any objects it has a reference to. It tries to check in the C struct for the pointer to the XML::Document object to mark its parent document ... but this is an illegal operation since the C struct has been freed. If the memory has been re-used, it's likely that we're going to segfault.

This is the first destructive operation I've seen from libxslt, and is making me reconsider a lot of assumptions we have made about libxml2/libxslt's memory model ...

I need to think a bit about the solution space here. 🙏

@flavorjones
Copy link
Member

In any case: the workaround you found makes sense: when you dup the document, it will default to a deep copy via xmlCopyDoc and so the destructive operation is invoked on newly-allocated C structs around which we don't have Ruby objects wrapped.

@flavorjones
Copy link
Member

Here's an even better demonstration of what's going on, which is that libxslt is modifying the document we pass in for transformation. This is surprising and probably should be considered a bug in libxslt.

#! /usr/bin/env ruby

require "bundler/inline"

gemfile do
  source "https://rubygems.org"
  gem "nokogiri", path: "."
end

require "nokogiri"

doc = Nokogiri::XML(<<~XML)
  <catalog>
    <entry>
      <title>     </title>
    </entry>
  </catalog>
XML

stylesheet = Nokogiri::XSLT(<<~XSL)
  <?xml version="1.0" encoding="UTF-8"?>
  <xsl:stylesheet version="1.0"
                  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  
    <xsl:strip-space elements="title" />
    
  </xsl:stylesheet>
XSL

doc.to_xml
# => "<?xml version=\"1.0\"?>\n" +
#    "<catalog>\n" +
#    "  <entry>\n" +
#    "    <title>     </title>\n" +
#    "  </entry>\n" +
#    "</catalog>\n"

stylesheet.transform(doc)

doc.to_xml
# => "<?xml version=\"1.0\"?>\n" +
#    "<catalog>\n" +
#    "  <entry>\n" +
#    "    <title/>\n" +
#    "  </entry>\n" +
#    "</catalog>\n"

Specifically, the blank text node is being removed from the original document which I think is surprising.

@tenderlove What do you think about doing a defensive xmlCopyDoc when calling xsltApplyStylesheet and other functions that can modify the doc out from under us? (This may also apply to the case you fixed in #2001.)

Copying the doc would obviously incur performance and memory overhead but may be worth it to avoid subtle bugs and to guarantee the document won't be modified in surprising ways.

@flavorjones
Copy link
Member

flavorjones commented Mar 9, 2023

@flavorjones
Copy link
Member

OK, I've got a proof-of-concept that will raise an exception if both of these things are true:

  • the XSL does space-stripping of some kind
  • the document has at least one empty Nokogiri::XML::Text object in it

This is similar to the workaround @tenderlove wrote for #2001. I'll polish it up and make a PR shortly.

flavorjones added a commit that referenced this issue Mar 9, 2023
this approach makes a defensive copy of the doc if there's a chance
the original may be modified in an unsafe way:

- if any spaces will be stripped
- if there are blank nodes

Fixes #2800
flavorjones added a commit that referenced this issue Mar 9, 2023
which it does if xsl:strip-space is used

this approach makes a defensive copy of the doc if there's a chance
the original may be modified in an unsafe way:

- if any spaces will be stripped
- if there are blank nodes

Fixes #2800
flavorjones added a commit that referenced this issue Mar 9, 2023
which it does if xsl:strip-space is used

this approach makes a defensive copy of the doc if there's a chance
the original may be modified in an unsafe way:

- if any spaces will be stripped
- if there are blank nodes

Fixes #2800
flavorjones added a commit that referenced this issue Mar 10, 2023
which it does be default when xsl:strip-space is used

this approach makes a defensive copy of the doc if there's a chance
the original may be modified in an unsafe way:

- if any spaces will be stripped
- and there are blank node objects that might be removed

Fixes #2800
@flavorjones flavorjones added this to the v1.15.0 milestone Apr 7, 2023
@flavorjones
Copy link
Member

This will be fixed in v1.15 when it's released, please watch the milestone for an idea of when that might happen (ideally within the month).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic/memory Segfaults, memory leaks, valgrind testing, etc.
Projects
None yet
2 participants