From 0c7aa83b3558b976936c4c40ba9ce41cf0c5f542 Mon Sep 17 00:00:00 2001 From: Dan Allen Date: Mon, 17 Oct 2022 01:54:59 -0600 Subject: [PATCH] resolves #4368 redo loop rather than using recursion to locate next line to process --- CHANGELOG.adoc | 4 ++++ lib/asciidoctor/reader.rb | 14 +++++++------- test/reader_test.rb | 18 ++++++++++++++++++ 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 360a558e9a..3ce9b56713 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -57,6 +57,10 @@ Improvements:: * Set linenums option on source block when line numbering is enabled (#3313) * Warn if include target is remote and `allow-uri-read` attribute is not set (#2284) +Bug Fixes:: + + * Redo loop rather than using recursion to locate next line to process; prevents stack limit error (#4368) + == 2.0.18 (2022-10-15) - @mojavelinux Improvements:: diff --git a/lib/asciidoctor/reader.rb b/lib/asciidoctor/reader.rb index d74fbd2382..a418fba8ff 100644 --- a/lib/asciidoctor/reader.rb +++ b/lib/asciidoctor/reader.rb @@ -129,16 +129,16 @@ def next_line_empty? # Returns the next line of the source data as a String if there are lines remaining. # Returns nothing if there is no more data. def peek_line direct = false - if direct || @look_ahead > 0 - @unescape_next_line ? ((line = @lines[-1]).slice 1, line.length) : @lines[-1] - elsif @lines.empty? - @look_ahead = 0 - nil - else + while true + return @unescape_next_line ? ((line = @lines[-1]).slice 1, line.length) : @lines[-1] if direct || @look_ahead > 0 + if @lines.empty? + @look_ahead = 0 + return + end # FIXME the problem with this approach is that we aren't # retaining the modified line (hence the @unescape_next_line tweak) # perhaps we need a stack of proxied lines - (process_line @lines[-1]) || peek_line + return (process_line @lines[-1]) || redo end end diff --git a/test/reader_test.rb b/test/reader_test.rb index 9014fa1fed..4b6c65a094 100644 --- a/test/reader_test.rb +++ b/test/reader_test.rb @@ -2819,6 +2819,24 @@ def process reader, target, attributes assert_empty logger end end + + test 'should not fail to process preprocessor directive that evaluates to false and has a large number of lines' do + lines = (%w(data) * 5000) * ?\n + input = <<~EOS + before + + ifdef::attribute-not-set[] + #{lines} + endif::attribute-not-set[] + + after + EOS + + doc = Asciidoctor.load input + assert_equal 2, doc.blocks.size + assert_equal 'before', doc.blocks[0].source + assert_equal 'after', doc.blocks[1].source + end end end end