Forum Bugs

Random-ish free()/malloc() errors

sfinktah
Hi,

I downloaded the latest version just to be sure... I'm finding a lot of this is happening:

prince: Loading document...
prince: loading HTML5 input: sia.html
prince: loading document: sia.html
prince(46416,0xacca5a28) malloc: *** error for object 0x1d67ab0: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
[....]
*** Mercury runtime: caught bus error ***
cause: non-existent physical address
address involved: 0x8bd
This may have been caused by a stack overflow, due to unbounded recursion.
exiting from signal handler
Bus error: 10



I have removed everything from the document that isn't HTML to make debugging easier... previous similar errors were resolved by manipulating <a> anchor elements, but that no longer seems to be possible.

Okay, this is especially strange:

prince *url removed* -vo sia.pdf (fails with some errors)
prince *url removed* -vo sia.pdf (works with some errors)

I guess that's the heap for you. Platform is OS X 10.8.4, btw.

Edited by sfinktah

mikeday
Yikes, thanks for that, we will track down this issue promptly.
mikeday
The issue appears to be a bug in the HTML parser triggered by nested <a> elements, which are illegal in HTML and will be split. We will fix this for the next maintenance release of Prince 9.

In the meantime, you can workaround the issue by closing <a> elements that would otherwise include blocks containing other <a> elements.
sfinktah
Wow, thankyou, such prompt service on a Saturday.

It's always about the anchors. Speaking of which, here are a few jquery functions I have written specifically to deal with them (for anyone else who has issues). I pre-process my documents in Chrome using javascript, then use "File -> Save As -> Complete". So no guarantees this works directly within prince.

Remove unreferenced anchors:
   function ($d) {
      $d.find('a[id]').each (function() {
         var $this = $(this);
         var id = $this.attr('id');
         if ($d.find('a[href="#'+id+'"]').length == 0) {
            $this.removeAttr('id');
            if (!this.children.length && !this.innerHTML) {
               if (this.attributes.length == 0 || ( this.attributes.length == 1 && $this.attr('class') ))
               $this.remove();
            } else {
               console.log('would remove, but it's hard', this, this.innerHTML);
            }
         }
      });
   }


Wrap floating anchors (from technique posted on this forum):
<style>
div.anchor-wrap {
   visibility: hidden;
   font-size: 0;
   line-height: 0;
}
</style>

   function ($d) {
      console.log("Finding widowed anchors");
      $d.find("a[id]:empty").each(function () {
            $(this).prepend("&#xA0;")
            .wrap($("<div class=anchor-wrap>"));
      });
   }


And if there is any chance you have old-style <a name=...> anchors, they'll need to be converted first:
   function ($d) {
      $d.find('a[name]').each (function() {
         var $this = $(this);
         var id = $this.attr('name');
         $this.attr('id', id);
         $this.removeAttr('name');
      });
   }



edit: and how obvious.. check for nested anchors:
   if ($('a a').length) alert('Nested Anchors, Prince will not process!');


non-jquery, should probably form part of a standard error testing kit or somesuch:
   for (var i=0, 
            myNodeList = document.getElementsByTagName('a'); 
            i < myNodeList.length; i++) 
      if (myNodeList[i].getElementsByTagName('a').length) 
         console.log('Nested Anchors');


edit: updated orphan anchor code to *not* cause the exact problem that caused this posting.

Edited by sfinktah