From bba8b7b6d25c150100d83d9a3b49fcef3ddf124a Mon Sep 17 00:00:00 2001 From: NAITOH Jun Date: Sat, 6 Sep 2025 14:26:55 +0900 Subject: [PATCH 1/2] Added a check for the presence of the root tag ## Why? GitHub: fix #289 --- lib/rexml/parsers/baseparser.rb | 5 +++++ test/parse/test_element.rb | 39 +++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/lib/rexml/parsers/baseparser.rb b/lib/rexml/parsers/baseparser.rb index 9304e96d..8fe287a7 100644 --- a/lib/rexml/parsers/baseparser.rb +++ b/lib/rexml/parsers/baseparser.rb @@ -266,6 +266,11 @@ def pull_event path = "/" + @tags.join("/") raise ParseException.new("Missing end tag for '#{path}'", @source) end + + unless @document_status == :in_element + raise ParseException.new("Malformed XML: No root element", @source) + end + return [ :end_document ] end return @stack.shift if @stack.size > 0 diff --git a/test/parse/test_element.rb b/test/parse/test_element.rb index f07a7d5a..de66447d 100644 --- a/test/parse/test_element.rb +++ b/test/parse/test_element.rb @@ -12,6 +12,45 @@ def parse(xml) end class TestInvalid < self + def test_top_level_no_tag + exception = assert_raise(REXML::ParseException) do + parse("") + end + assert_equal(<<-DETAIL.chomp, exception.to_s) +Malformed XML: No root element +Line: 0 +Position: 0 +Last 80 unconsumed characters: + + DETAIL + end + + def test_top_level_no_tag_with_xml_declaration + exception = assert_raise(REXML::ParseException) do + parse("") + end + assert_equal(<<-DETAIL.chomp, exception.to_s) +Malformed XML: No root element +Line: 1 +Position: 21 +Last 80 unconsumed characters: + + DETAIL + end + + def test_top_level_no_tag_with_comment + exception = assert_raise(REXML::ParseException) do + parse("") + end + assert_equal(<<-DETAIL.chomp, exception.to_s) +Malformed XML: No root element +Line: 1 +Position: 16 +Last 80 unconsumed characters: + + DETAIL + end + def test_top_level_end_tag exception = assert_raise(REXML::ParseException) do parse("") From c0f1cd55f3231b8c2a2164441df876eda93f32e6 Mon Sep 17 00:00:00 2001 From: NAITOH Jun Date: Sat, 6 Sep 2025 14:50:44 +0900 Subject: [PATCH 2/2] fix test code --- test/parse/test_attribute_list_declaration.rb | 6 +++--- test/parse/test_comment.rb | 2 +- test/parse/test_entity_declaration.rb | 8 ++++---- test/parse/test_processing_instruction.rb | 4 ++-- test/test_contrib.rb | 2 +- test/test_core.rb | 18 +++++++----------- test/test_document.rb | 6 +++--- test/test_entity.rb | 2 +- 8 files changed, 22 insertions(+), 26 deletions(-) diff --git a/test/parse/test_attribute_list_declaration.rb b/test/parse/test_attribute_list_declaration.rb index 43882528..4fa54218 100644 --- a/test/parse/test_attribute_list_declaration.rb +++ b/test/parse/test_attribute_list_declaration.rb @@ -10,9 +10,9 @@ class TestParseAttributeListDeclaration < Test::Unit::TestCase def test_linear_performance_space seq = [10000, 50000, 100000, 150000, 200000] assert_linear_performance(seq, rehearsal: 10) do |n| - REXML::Document.new("]>") + " root v CDATA #FIXED \"test\">]>") end end @@ -23,7 +23,7 @@ def test_linear_performance_tab_and_gt "\t" * n + "root value CDATA \"" + ">" * n + - "\">]>") + "\">]>") end end end diff --git a/test/parse/test_comment.rb b/test/parse/test_comment.rb index 6339835d..d00c8f32 100644 --- a/test/parse/test_comment.rb +++ b/test/parse/test_comment.rb @@ -174,7 +174,7 @@ def test_after_root def test_linear_performance_top_level_gt seq = [10000, 50000, 100000, 150000, 200000] assert_linear_performance(seq, rehearsal: 10) do |n| - REXML::Document.new('') + REXML::Document.new('') end end diff --git a/test/parse/test_entity_declaration.rb b/test/parse/test_entity_declaration.rb index 81d95b58..0cbd4550 100644 --- a/test/parse/test_entity_declaration.rb +++ b/test/parse/test_entity_declaration.rb @@ -523,7 +523,7 @@ def test_linear_performance_entity_value_gt assert_linear_performance(seq, rehearsal: 10) do |n| REXML::Document.new("" * n + - "\">]>") + "\">]>") end end @@ -532,7 +532,7 @@ def test_linear_performance_entity_value_gt_right_bracket assert_linear_performance(seq, rehearsal: 10) do |n| REXML::Document.new("]" * n + - "\">]>") + "\">]>") end end @@ -541,7 +541,7 @@ def test_linear_performance_system_literal_in_system_gt_right_bracket assert_linear_performance(seq, rehearsal: 10) do |n| REXML::Document.new("]" * n + - "\">]>") + "\">]>") end end @@ -550,7 +550,7 @@ def test_linear_performance_system_literal_in_public_gt_right_bracket assert_linear_performance(seq, rehearsal: 10) do |n| REXML::Document.new("]" * n + - "\">]>") + "\">]>") end end end diff --git a/test/parse/test_processing_instruction.rb b/test/parse/test_processing_instruction.rb index 70d17747..723a8cd0 100644 --- a/test/parse/test_processing_instruction.rb +++ b/test/parse/test_processing_instruction.rb @@ -237,14 +237,14 @@ def test_content_question def test_linear_performance_gt seq = [10000, 50000, 100000, 150000, 200000] assert_linear_performance(seq, rehearsal: 10) do |n| - REXML::Document.new("" * n + " ?>") + REXML::Document.new("" * n + " ?>") end end def test_linear_performance_tab seq = [10000, 50000, 100000, 150000, 200000] assert_linear_performance(seq, rehearsal: 10) do |n| - REXML::Document.new(" ?>") + REXML::Document.new(" ?>") end end end diff --git a/test/test_contrib.rb b/test/test_contrib.rb index 23ee35b1..0b66672c 100644 --- a/test/test_contrib.rb +++ b/test/test_contrib.rb @@ -472,7 +472,7 @@ def test_maintain_dtd %extern-packages; %extern-common; -]>} +]>} doc = Document.new( src ) doc.write( out="" ) src = src.tr('"', "'") diff --git a/test/test_core.rb b/test/test_core.rb index 651056f2..c998490e 100644 --- a/test/test_core.rb +++ b/test/test_core.rb @@ -329,7 +329,7 @@ def test_instruction REXML::Formatters::Default.new.write( instruction, out = "" ) assert_equal(source, out) - d = Document.new( source ) + d = Document.new( source + "") instruction2 = d[0] assert_equal(instruction.to_s, instruction2.to_s) @@ -875,7 +875,7 @@ def test_entities def test_element_decl element_decl = Source.new(" -]>") +]>") doc = Document.new( element_decl ) d = doc[0] assert_equal("", d.to_s.split(/\n/)[1].strip) @@ -1329,7 +1329,7 @@ def test_ticket_53 end def test_ticket_52 - source = "" + source = "" d = REXML::Document.new(source) d.write(k="") assert_equal( source, k ) @@ -1408,10 +1408,10 @@ def test_ticket_48_part_II end def test_ticket_88 - doc = REXML::Document.new("") - assert_equal("", doc.to_s) - doc = REXML::Document.new("") - assert_equal("", doc.to_s) + doc = REXML::Document.new("") + assert_equal("", doc.to_s) + doc = REXML::Document.new("") + assert_equal("", doc.to_s) end def test_ticket_85 @@ -1550,10 +1550,6 @@ def test_ticket_138 REXML::Document.new(doc.root.to_s).root.attributes.to_h) end - def test_empty_doc - assert(REXML::Document.new('').children.empty?) - end - private def attribute(name, value) REXML::Attribute.new(name, value) diff --git a/test/test_document.rb b/test/test_document.rb index 39b6c337..71fed190 100644 --- a/test/test_document.rb +++ b/test/test_document.rb @@ -151,11 +151,11 @@ def test_tag_in_cdata_with_not_ascii_only_but_ascii8bit_encoding_source def test_xml_declaration_standalone bug2539 = '[ruby-core:27345]' - doc = REXML::Document.new('') + doc = REXML::Document.new('') assert_equal('no', doc.stand_alone?, bug2539) - doc = REXML::Document.new('') + doc = REXML::Document.new('') assert_equal('no', doc.stand_alone?, bug2539) - doc = REXML::Document.new('') + doc = REXML::Document.new('') assert_equal('no', doc.stand_alone?, bug2539) end diff --git a/test/test_entity.rb b/test/test_entity.rb index 89f83894..03f268dd 100644 --- a/test/test_entity.rb +++ b/test/test_entity.rb @@ -79,7 +79,7 @@ def test_constructor - ]>} + ]>} d = REXML::Document.new( source ) dt = d.doctype