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

FB2: Maximum call stack size exceeded #935

Closed
pok49 opened this issue Sep 4, 2022 · 2 comments
Closed

FB2: Maximum call stack size exceeded #935

pok49 opened this issue Sep 4, 2022 · 2 comments
Labels
bug Something isn't working

Comments

@pok49
Copy link

pok49 commented Sep 4, 2022

I've installed Foliate and tried some ebooks. Some of them opened as expected, but quite a few failed with the error message screen:

:-(
Could not open file
Maximum call stack size exceeded.
[Open Another File]

A small fb2 book of this sort is available here.

I've reduced it to a smaller test (1214 bytes; I'll try to attach it). The problem seems to be due to hyperlinks in the text.

I am not alone in experiencing this problem; there are similar complaints in the Net, e.g. in this post:

Ответ на: комментарий от AP 07.04.22 23:18:41
Спасибо за наводку. Выглядит симпатично, правда некоторые fb2 книги не открывает, валится с «Maximum call stack size exceeded». Кто-нибудь сталкивался с таким?

My testing environment:
% uname -a
Linux Eee901 4.9.0-279-antix.1-486-smp #1 SMP Sun Aug 8 20:59:37 EEST 2021 i686 GNU/Linux
%
% dpkg-query -l 'foliate'
||/ Name Version Architecture Description
+++-===============================-============-============-================>
ii com.github.johnfactotum.foliate 2.6.4 all Simple and modern
fail17.fb2.zip

@pok49 pok49 added the bug Something isn't working label Sep 4, 2022
@johnfactotum johnfactotum changed the title Maximum call stack size exceeded FB2: Maximum call stack size exceeded Sep 9, 2022
@johnfactotum
Copy link
Owner

Thanks for reporting this. It's indeed caused by hyperlinks. The smaller test case only test for links within a section, but the larger one seems to contain also links to other sections which then links back to the original section. So I think one needs to keep track of all the sections that one has traversed before to prevent infinite recursion. Here's a quick fix I came up with:

diff --git a/src/web/webpub.js b/src/web/webpub.js
index 5479c16..36cd89b 100644
--- a/src/web/webpub.js
+++ b/src/web/webpub.js
@@ -156,7 +156,8 @@ const webpubFromFB2 = async (uri, filename) => {
 
 const fb2Sections = new Map()
 
-const fb2ToHtml = (fb2, node, itemFromElement, isSection) => {
+const fb2ToHtml = (fb2, node, itemFromElement, isSection, parents = []) => {
+    parents.push(node)
     const walk = (fb2, node, f) => {
         const [output, childF, post = x => x] = f(fb2, node)
         node = node.firstChild
@@ -229,9 +230,8 @@ const fb2ToHtml = (fb2, node, itemFromElement, isSection) => {
                     let note = fb2.getElementById(id)
                     if (!note) return [el]
                     while (!note.matches('body > *')) note = note.parentElement
-                    let item = fb2Sections.get(note)
-                    if (!item && itemFromElement) item = itemFromElement(note)
-                    if (item) el.setAttribute('href', item.href + '#' + id)
+                    const item = itemFromElement ? itemFromElement(note, parents) : null
+                    if (item) el.setAttribute('href', (item?.href ?? '') + '#' + id)
                 }
                 return [el]
             }
@@ -488,9 +488,10 @@ const processFB2 = async (fb2, blob, filename) => {
     const styleUrl = URL.createObjectURL(styleBlob)
 
     let i = 0
-    const itemFromElement = x => {
+    const itemFromElement = (x, parents = []) => {
+        if (parents.includes(x)) return
         if (fb2Sections.has(x)) return fb2Sections.get(x)
-        const section = fb2ToHtml(fb2, x, itemFromElement)
+        const section = fb2ToHtml(fb2, x, itemFromElement, false, parents)
 
         const titles = [
             ...section.querySelectorAll(':scope > section > header') || []]
@@ -540,7 +541,7 @@ const processFB2 = async (fb2, blob, filename) => {
     const toc = []
     bodies.forEach((body, i) => {
         const name = body.getAttribute('name')
-        const sections = [...body.children].map(itemFromElement)
+        const sections = [...body.children].map(x => itemFromElement(x))
         readingOrder.push(...sections)
 
         const titledSections = sections.filter(x => x.title)

Would be great if you could test and see if it fixes the issue and if it causes any regressions. (I guess I should really set up some tests when I have time.)

@johnfactotum
Copy link
Owner

Fixed in the gtk4 branch. With the new renderer (#962), there's no need to pre-generate blobs for every section, as a result there's no need for recursive loading linked sections anymore.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants