manuels/texlive.js

Large PDFs: RangeError on String.fromCharCode.apply...

jvilk opened this issue · 9 comments

If you use String.fromCharCode.apply(String, some_array) with an array that is too large (typically 64K), it will result in a stack overflow in most browsers.

This is a problem here:
https://github.com/manuels/texlive.js/blob/master/pre.js#L97

hmm, then we need another (fast) alternative.
Do you have an idea what function we could use instead?

This will be fast enough (and is the solution I used), unless the file produced is multiple megabytes long:

          var res2 = "";
          for (var i = 0; i < res.length; i++) {
            res2 += String.fromCharCode(res[i]);
          }
          res = res2;

If you want faster, then you'll want to call String.fromCharCode.apply(String, some_array) on batches of <64K bytes.

(Note that the problem is not that you are using String.fromCharCode, it is that you are calling it with 64K+ individual arguments, which all have to fit on the stack.)

I'm having this issue with the default demo in index.html: res ends up being a Uint8Array[87281]. The demo works if I severely pare down the content.

@jvilk sorry, I kind of lost track on this bug.
@xylo04 Thanks for the pull request, but for performance reasons I'd prefer something like
(pseudocode)

var chunk = 32*1024;
for (var i = 0; i < res.length/chunk; i++) {
    res2 += String.fromCharCode(res[i*chunk:(i+1)*chunk]);
}
res2 += String.fromCharCode(res[i*chunk:]);

SGTM, I wasn't really happy with my original solution but it got me working. I'll put together another pull request using chunking.

FYI, I did try 32K chunks and still ran into RangeErrors; bumped it down to 8K chunks to give it some headroom.

jvilk commented

Yeah, AFAIK the amount of arguments you can use will depend on the current size of the stack, which depends on how many functions you have called prior to calling this method and the size of the arguments to them. 8K seems like a reasonably safe number.

Should be fixed by @xylo04's pull request. Thanks, guys!