[ 
https://issues.apache.org/jira/browse/PDFBOX-5758?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Axel Howind updated PDFBOX-5758:
--------------------------------
    Description: 
When unmapping is not supported, PdfBox throws an ExceptionInInitializerError 
that is not recoverable. The reason is that in IOUtils, the UNMAPPER static 
field is initialized before the Logger is created and when the unmapper can not 
be created, PdfBox tries to write an error message to the log:
 
{code:java}
public final class IOUtils
{
    ...

    static
    {
        UNMAPPER = Optional.ofNullable(AccessController
                .doPrivileged((PrivilegedAction<Consumer<ByteBuffer>>) 
IOUtils::unmapper));
    }

    /**
     * Log instance.
     */
    private static final Logger LOG = LogManager.getLogger(IOUtils.class);

    ...

private static Consumer<ByteBuffer> unmapper()
{
    final Lookup lookup = lookup();
    try
    {
        ...
    }
    catch (SecurityException se)
    {
        LOG.error(
                "Unmapping is not supported because of missing permissions. 
Please grant at least the following permissions: 
RuntimePermission(\"accessClassInPackage.sun.misc\") "
                        + " and ReflectPermission(\"suppressAccessChecks\")",
                se);

    }
    catch (ReflectiveOperationException | RuntimeException e)
    {
        LOG.error("Unmapping is not supported.", e);
    }
    return null;
}{code}
 

UPDATE:

It is important to notice that this bug completely prevents loading of the 
IOUtils class (and in most cases crash the program), regardless of whether any 
functionality using mapping/unmapping is even used. So I think this should be 
considered a high priority bug.

Excerpt of stacktrace:
{noformat}
Caused by: java.lang.ExceptionInInitializerError: Exception 
java.lang.NullPointerException [in thread "ForkJoinPool-1-worker-3"]
        at 
docdiff@1.6.0-SNAPSHOT/org.apache.pdfbox.io.IOUtils.unmapper(IOUtils.java:278) 
~[docdiff:?]
        at 
java.base/java.security.AccessController.doPrivileged(AccessController.java:319)
 ~[?:?]
        at 
docdiff@1.6.0-SNAPSHOT/org.apache.pdfbox.io.IOUtils.<clinit>(IOUtils.java:64) 
~[docdiff:?]
        at 
docdiff@1.6.0-SNAPSHOT/org.apache.pdfbox.Loader.loadPDF(Loader.java:196) 
~[docdiff:?]
        at 
docdiff@1.6.0-SNAPSHOT/org.apache.pdfbox.Loader.loadPDF(Loader.java:176) 
~[docdiff:?]
        at 
docdiff@1.6.0-SNAPSHOT/org.apache.pdfbox.Loader.loadPDF(Loader.java:159) 
~[docdiff:?]{noformat}
Line 278 is:
{code:java}
LOG.error("Unmapping is not supported.", e);{code}
The reason is that LOG is initialized after UNMAPPER, but the initialisation of 
UNMAPPER accesses LOG in case of an error. That's due to this rule in the 
[JLS|[https://docs.oracle.com/javase/specs/jls/se11/html/jls-12.html#jls-12.4.2]]:
{quote}Next, execute either the class variable initializers and static 
initializers of the class, or the field initializers of the interface, in 
textual order, as though they were a single block.
{quote}
By moving the LOG initialization to the beginning of the class, the UNMAPPER 
gets assigned to an empty Optional and no exception is thrown.

I encountered this bug when jpackaging an application where obviously something 
in the generated application is missing that is needed for the unmapper to 
work. This was really a little bit hard to debug, because I logged all types of 
exceptions, but an Error is a Throwable that does not derive from Exception and 
usually just aborts the program and no log messages were generated. And the 
problem only happened when the program was not started with the debugger.

  was:
When unmapping is not supported, PdfBox throws an ExceptionInInitializerError 
that is not recoverable. The reason is that in IOUtils, the UNMAPPER static 
field is initialized before the Logger is created and when the unmapper can not 
be created, PdfBox tries to write an error message to the log:
 
{code:java}
public final class IOUtils
{
    ...

    static
    {
        UNMAPPER = Optional.ofNullable(AccessController
                .doPrivileged((PrivilegedAction<Consumer<ByteBuffer>>) 
IOUtils::unmapper));
    }

    /**
     * Log instance.
     */
    private static final Logger LOG = LogManager.getLogger(IOUtils.class);

    ...

private static Consumer<ByteBuffer> unmapper()
{
    final Lookup lookup = lookup();
    try
    {
        ...
    }
    catch (SecurityException se)
    {
        LOG.error(
                "Unmapping is not supported because of missing permissions. 
Please grant at least the following permissions: 
RuntimePermission(\"accessClassInPackage.sun.misc\") "
                        + " and ReflectPermission(\"suppressAccessChecks\")",
                se);

    }
    catch (ReflectiveOperationException | RuntimeException e)
    {
        LOG.error("Unmapping is not supported.", e);
    }
    return null;
}{code}
 


> ExceptionInInitializerError when unmapping is not supported
> -----------------------------------------------------------
>
>                 Key: PDFBOX-5758
>                 URL: https://issues.apache.org/jira/browse/PDFBOX-5758
>             Project: PDFBox
>          Issue Type: Bug
>          Components: IO
>            Reporter: Axel Howind
>            Priority: Major
>              Labels: patch
>         Attachments: 
> PDFBOX-5758__ExceptionInInitializerError_when_unmapping_is_not_supported.patch
>
>
> When unmapping is not supported, PdfBox throws an ExceptionInInitializerError 
> that is not recoverable. The reason is that in IOUtils, the UNMAPPER static 
> field is initialized before the Logger is created and when the unmapper can 
> not be created, PdfBox tries to write an error message to the log:
>  
> {code:java}
> public final class IOUtils
> {
>     ...
>     static
>     {
>         UNMAPPER = Optional.ofNullable(AccessController
>                 .doPrivileged((PrivilegedAction<Consumer<ByteBuffer>>) 
> IOUtils::unmapper));
>     }
>     /**
>      * Log instance.
>      */
>     private static final Logger LOG = LogManager.getLogger(IOUtils.class);
>     ...
> private static Consumer<ByteBuffer> unmapper()
> {
>     final Lookup lookup = lookup();
>     try
>     {
>         ...
>     }
>     catch (SecurityException se)
>     {
>         LOG.error(
>                 "Unmapping is not supported because of missing permissions. 
> Please grant at least the following permissions: 
> RuntimePermission(\"accessClassInPackage.sun.misc\") "
>                         + " and ReflectPermission(\"suppressAccessChecks\")",
>                 se);
>     }
>     catch (ReflectiveOperationException | RuntimeException e)
>     {
>         LOG.error("Unmapping is not supported.", e);
>     }
>     return null;
> }{code}
>  
> UPDATE:
> It is important to notice that this bug completely prevents loading of the 
> IOUtils class (and in most cases crash the program), regardless of whether 
> any functionality using mapping/unmapping is even used. So I think this 
> should be considered a high priority bug.
> Excerpt of stacktrace:
> {noformat}
> Caused by: java.lang.ExceptionInInitializerError: Exception 
> java.lang.NullPointerException [in thread "ForkJoinPool-1-worker-3"]
>         at 
> docdiff@1.6.0-SNAPSHOT/org.apache.pdfbox.io.IOUtils.unmapper(IOUtils.java:278)
>  ~[docdiff:?]
>         at 
> java.base/java.security.AccessController.doPrivileged(AccessController.java:319)
>  ~[?:?]
>         at 
> docdiff@1.6.0-SNAPSHOT/org.apache.pdfbox.io.IOUtils.<clinit>(IOUtils.java:64) 
> ~[docdiff:?]
>         at 
> docdiff@1.6.0-SNAPSHOT/org.apache.pdfbox.Loader.loadPDF(Loader.java:196) 
> ~[docdiff:?]
>         at 
> docdiff@1.6.0-SNAPSHOT/org.apache.pdfbox.Loader.loadPDF(Loader.java:176) 
> ~[docdiff:?]
>         at 
> docdiff@1.6.0-SNAPSHOT/org.apache.pdfbox.Loader.loadPDF(Loader.java:159) 
> ~[docdiff:?]{noformat}
> Line 278 is:
> {code:java}
> LOG.error("Unmapping is not supported.", e);{code}
> The reason is that LOG is initialized after UNMAPPER, but the initialisation 
> of UNMAPPER accesses LOG in case of an error. That's due to this rule in the 
> [JLS|[https://docs.oracle.com/javase/specs/jls/se11/html/jls-12.html#jls-12.4.2]]:
> {quote}Next, execute either the class variable initializers and static 
> initializers of the class, or the field initializers of the interface, in 
> textual order, as though they were a single block.
> {quote}
> By moving the LOG initialization to the beginning of the class, the UNMAPPER 
> gets assigned to an empty Optional and no exception is thrown.
> I encountered this bug when jpackaging an application where obviously 
> something in the generated application is missing that is needed for the 
> unmapper to work. This was really a little bit hard to debug, because I 
> logged all types of exceptions, but an Error is a Throwable that does not 
> derive from Exception and usually just aborts the program and no log messages 
> were generated. And the problem only happened when the program was not 
> started with the debugger.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@pdfbox.apache.org
For additional commands, e-mail: dev-h...@pdfbox.apache.org

Reply via email to