PDF Viewing Support (poppler-qt4)

Eskil Abrahamsen Blomfeldt eblomfel at trolltech.com
Fri Feb 15 14:55:47 CET 2008


Adam Batkin wrote:
> The interesting bit is the typesystem file for the PdfDocument class:
>
>         <object-type name="PdfDocument">
>                 <modify-function signature="page(int)const" 
> access="private" rename="page_helper">
>                         <modify-argument index="return">
>                                 <reference-count action="ignore"/>
>                                 <define-ownership class="java" 
> owner="java"/>

Is the PdfPage a QObject? If not, then you should be careful doing this. 
The reason is that if Java has the ownership of a C++ object, the C++ 
object will be destroyed along with the Java object when the GC sees 
fit. This of course means that you should make sure you have no dangling 
references to the C++ object on the C++ side.

The other caveat is that if the class is not a QObject, then special 
rules apply. Since we do not control the C++ object's destructor, we 
have no control over when C++ object is destroyed. Therefore we cannot 
reuse the Java objects we automatically create to map the C++ objects.

I.e. here's the danger I see:

1. User calls Java version of page()
2. This in turn invokes the generated JNI-based code to convert the 
PdfPage pointer to a Java object.
3. Conversion code creates a Java object bound to the C++ object with 
ownership of the C++ object. (the conversion code *always* creates a new 
Java object, since there is no way of detecting whether the PdfPage 
pointer has been mapped before.)
4. User calls page() again, with the same index as before.
5. C++ returns the same PdfPage pointer because we requested the same page.
6. Conversion code creates a second Java object bound to the same C++ 
object, and this also has ownership of the C++ object.
7. One of the two Java objects goes out of scope and GC kills it.
8. The Java object owns the C++ object, so the finalizer destroys the 
C++ object
9. The second Java object is still alive and tries to access the 
now-invalid data.

If this is the case, you should be able to crash pretty easily by 
calling e.g. page(0) a bunch of times, only retaining the last 
reference, and then trying to call a method on this.

If PdfPage is a subclass of QObject, then other rules apply, because we 
can track the destruction of QObjects, so you should only get a single 
Java object per C++ object, and the code above should work, I think. The 
default ownership in that case is that C++ owns both its own object and 
the Java object and is not garbage collected.

Again, this should be easy to test. You should also be able to check 
that you are in fact getting the same Java object with each call to 
page() for a specific index by checking that the  identity of the two 
objects in Java are equal (if (object1 == object2) ...)

>
> I did some testing with a giant List of every PdfPage ever obtained, 
> and made sure that no PdfDocuments were ever garbage collected 
> (without the <modify-argument bits the PdfDocuments would often be 
> GCed too early).

I'm not sure why this would happen, though. The default behavior is that 
the return value of page() has what we call "split ownership" which 
means that Java is allowed to garbage collect the Java object, but C++ 
owns the C++ object so this will live until it's deleted.

If they are QObjects, then the Java objects of the PdfPage objects 
should not be garbage collected until the corresponding C++ object is 
deleted. The PdfDocument object, granted it's created in Java, should 
live as long as there are references to it, which should be guaranteed 
by the reference set in the PdfPage object.

So, as far as I can see: as long as you have a reference to the PdfPage 
object, this has a reference to the PdfDocument object, the PdfDocument 
object should remain in memory. How did you confirm its deletion?

It might be that something in this analysis is wrong, though, since it's 
all from the top of my head, but you might want to keep alert to this 
having consequences further down the road in case I am right. :-)

Very cool project, by the way. I wish you the best of luck and will help 
as much as I can with any questions you have.

-- Eskil




More information about the Qt-jambi-interest mailing list