Using PdfFileInfo on passwort ptrotected file results in allocation of a lot of memory in SOH

Hello,
I’m part of an organization using Aspose.Total. In our .NET code base we use Aspose.PDF for pdf operations.

One purpose is to detect if a PDF is password protected. To achieve this we use a PdfFileInfo objects IsEncrypted property. This works as expected and doesn’t lead to any issues itself.

But when we run it in Rider we get a warning from the “Dynamic Program Analysis” tool that the PdfFileInfo object “allocates a lot of memory in the Small Object Heap”. This seems to happen due to a Boxing of a byte[] to a Byte[].
This warning only occurs on password protected pdfs and not on pdfs without password protection.

Is this boxing intentional or could it be avoided?

The code we use for detecting if a pdf is password protected

private static bool IsPdfPasswordProtected(Stream file)
{
    using var pdfFileInfo = new PdfFileInfo(file);
    var isPdfPasswordProtected = pdfFileInfo.IsEncrypted;
    pdfFileInfo.Close();
    return isPdfPasswordProtected;
}

The warning from rider:
Small Object Heap: code that allocates a lot of memory in SOH
Allocated object type: Byte[]
Last observation: 3/16/2023 12:28 PM 29543-aspose-pw-protected-pdf
Allocated size: 185.3 MB

The stack trace: (removed private path information)

at System.IO.MemoryStream.set_Capacity(int)
at System.IO.MemoryStream.EnsureCapacity(int)
at System.IO.MemoryStream.Write(byte[], int, int)
at #=z4TFq0HxjjOPp9KWw1nqEq9PSuXe9Hioz1gBkRbyZhrmPYAtr_Xqb8LvRHuD4.#=z7uIeWQg=(Stream)
at #=zwqflDtf6DW8ei5d5P$B5Z9MD_$IuYyZAR6WkMW8=.#=zUqm2wc8FtTOS(byte[], byte[], byte[])
at #=zwqflDtf6DW8ei5d5P$B5Z9MD_$IuYyZAR6WkMW8=.#=zVxpQhgg1x9oN(byte[], byte[], byte[], byte[], byte[])
at #=zwqflDtf6DW8ei5d5P$B5Z9MD_$IuYyZAR6WkMW8=.#=zl4AWbIeoS_wC(byte[], byte[], byte[], byte[], byte[], byte[])
at #=zwqflDtf6DW8ei5d5P$B5Z9MD_$IuYyZAR6WkMW8=.#=zl4AWbIeoS_wC(String)
at #=zwqflDtf6DW8ei5d5P$B5Z9MD_$IuYyZAR6WkMW8=.#=z6kj9Gso=()
at #=zxDmjvytyzJmXnqZWKkB3l5QAt8tJIQr45Qy2YTc=.#=zmyp$mHA=(#=z2tvFRc$7ttclcolCnC5rFLOy4LGGla6oXgX3bIE=)
at #=zn9OIGtcwnLGvCHokiLnXHCaXpug1kHjLNvKdHhc=..ctor(#=z7Ev0AJeSlzxSyqSMKqtWc9aF7kF7MFUPgUpzzN75_8fh, byte[], int, String)
at #=zn9OIGtcwnLGvCHokiLnXHCaXpug1kHjLNvKdHhc=.#=znA5JloQ=(#=z7Ev0AJeSlzxSyqSMKqtWc9aF7kF7MFUPgUpzzN75_8fh, byte[], String)
at #=zeb3iQ83WFbhEUjA3gMVIJGYD1fBT.#=zv$yPh1Y=()
at #=zeb3iQ83WFbhEUjA3gMVIJGYD1fBT..ctor(#=z7Ev0AJeSlzxSyqSMKqtWc9aF7kF7MFUPgUpzzN75_8fh, #=zTm43NOuoh6S3l2IBRYgtRVZNO9NUP311rQ==, String)
at #=zfSOHWDzeP3du6d282MS2a8wVzFO7UJ4rFbqz5Xg=.#=zwbmRKQE=(#=z7Ev0AJeSlzxSyqSMKqtWc9aF7kF7MFUPgUpzzN75_8fh, #=zTm43NOuoh6S3l2IBRYgtRVZNO9NUP311rQ==, String)
at #=zMjI90_nMcWFfuefXMx8fKcnFEokHIef1buwfWL4=.#=zkeG1LVy8RcxS()
at #=zMjI90_nMcWFfuefXMx8fKcnFEokHIef1buwfWL4=.#=zUs$3tyeECoxYJMjpanmjwAHDT_w4zvAj7FTFhg8mKQcFbM0deg==()
at #=qr65pjlhKkc1qVywrAPsvEBMPtPH_aUVvTPLWXgNv1sA=.#=ztZRuI1lPmKF3dn8hiO$0l6oVOUCfFeB5D1lxdRn5JWnL(MethodBase, Object, Object[], bool)
at #=qr65pjlhKkc1qVywrAPsvEBMPtPH_aUVvTPLWXgNv1sA=.#=zf3QbpbTu69$fee7f5tpQmNU=(MethodBase, bool)
at #=qr65pjlhKkc1qVywrAPsvEBMPtPH_aUVvTPLWXgNv1sA=.#=zIuHflav0CdqPAb0IW1GfFME=(#=qr65pjlhKkc1qVywrAPsvEBMPtPH_aUVvTPLWXgNv1sA=, #=qm_50B3$cVADTp5H6iOJ9ZH6KP2xlHeId0ijDxcHINnY=)
at #=qr65pjlhKkc1qVywrAPsvEBMPtPH_aUVvTPLWXgNv1sA=.#=zR_9OX9XHKGJRsKaX$K_ufYo=()
at #=qr65pjlhKkc1qVywrAPsvEBMPtPH_aUVvTPLWXgNv1sA=.#=zmwh8mkJVPFZYjy$abcec5is=(bool)
at #=qr65pjlhKkc1qVywrAPsvEBMPtPH_aUVvTPLWXgNv1sA=.#=zox2kioPTeleVwE5GR9mijYIitvRGKf3CDg==()
at #=qr65pjlhKkc1qVywrAPsvEBMPtPH_aUVvTPLWXgNv1sA=.#=zdqTswa6T6$nlz$KLzdZ2_V5weRdgZf20PQ==(Object[], Type[], Type[], Object[])
at #=qr65pjlhKkc1qVywrAPsvEBMPtPH_aUVvTPLWXgNv1sA=.#=zgtdcuWd_WedWKnt8eUvWbTznhNvJ(Stream, int, Object[], Type[], Type[], Object[])
at #=qr65pjlhKkc1qVywrAPsvEBMPtPH_aUVvTPLWXgNv1sA=.#=zSAZszoDxjvdmZsf_wsSuGMlTtG6IImDQ6zxCQwaH9_CM(int, Type[], Type[], bool)
at #=qr65pjlhKkc1qVywrAPsvEBMPtPH_aUVvTPLWXgNv1sA=.#=zR_9OX9XHKGJRsKaX$K_ufYo=()
at #=qr65pjlhKkc1qVywrAPsvEBMPtPH_aUVvTPLWXgNv1sA=.#=zmwh8mkJVPFZYjy$abcec5is=(bool)
at #=qr65pjlhKkc1qVywrAPsvEBMPtPH_aUVvTPLWXgNv1sA=.#=zox2kioPTeleVwE5GR9mijYIitvRGKf3CDg==()
at #=qr65pjlhKkc1qVywrAPsvEBMPtPH_aUVvTPLWXgNv1sA=.#=zdqTswa6T6$nlz$KLzdZ2_V5weRdgZf20PQ==(Object[], Type[], Type[], Object[])
at #=qr65pjlhKkc1qVywrAPsvEBMPtPH_aUVvTPLWXgNv1sA=.#=z_xveqqeYdCic85D_3ypsMxbTZvW4(Stream, String, Object[], Type[], Type[], Object[])
at #=qr65pjlhKkc1qVywrAPsvEBMPtPH_aUVvTPLWXgNv1sA=.#=z$cFyffCcAuFgt0sD8LJGuV4=(Stream, String, Object[])
at #=qr65pjlhKkc1qVywrAPsvEBMPtPH_aUVvTPLWXgNv1sA=.#=zZei0i1bFXhDC110Sl4BWBjn40baro8qFYCgy0rgKlEzz(Stream, String, Object[])
at #=zxdnv8OAgjout8sBl4mWyx7lPPDI1WCCd8w==.#=zBPB$lIj2$h7v(String, bool, StringBuilder, #=zlTHDfvWJ7FfvS41SmNs7ZlYr3_8IHPGP7zYDvUg=)
at #=zxdnv8OAgjout8sBl4mWyx7lPPDI1WCCd8w==..ctor(Stream, String, bool)
at #=zxdnv8OAgjout8sBl4mWyx7lPPDI1WCCd8w==..ctor(Stream)
at #=zfSOHWDzeP3du6d282MS2a8wVzFO7UJ4rFbqz5Xg=.#=zKUUVzYw=(Stream)
at #=zD8DOzSCi_0OZxy26L1$cjL9vpSipcXbYlA==..ctor(Stream)
at #=zfSOHWDzeP3du6d282MS2a8wVzFO7UJ4rFbqz5Xg=.#=zj2_2b9n8FE$f(Stream)
at #=zfRty0BGpSXrXG20dY_Avpj3Q5zWa.#=zJFtDuTs=(Stream)
at #=zfRty0BGpSXrXG20dY_Avpj3Q5zWa..ctor(Stream)
at Aspose.Pdf.Document.#=z2S47uYQ=(Stream, String)
at Aspose.Pdf.Document..ctor(Stream, String)
at Aspose.Pdf.Facades.Facade.BindPdf(Stream, String)
at Aspose.Pdf.Facades.PdfFileInfo.BindPdf(Stream, String)
at Aspose.Pdf.Facades.PdfFileInfo..ctor(Stream)
at _29543_aspose_pw_protected_pdf.Program.IsPdfPasswordProtected(Stream) in .../29543-aspose-pw-protected-pdf/Program.cs:line 30 column 13
at _29543_aspose_pw_protected_pdf.Program.Main(String[]) in .../29543-aspose-pw-protected-pdf/Program.cs:line 23 column 17

@JannikEsser

Does it happen with every PDF document you are trying to process? OR with a specific one? Please share a sample document for our reference so that we can test the scenario in our environment and address it accordingly.

PS: Please make sure to use latest version of the API before sharing the requested details.

This problem occurs with every password protected pdf I’ve tested it on. As a sample I’ve appended a pdf I created from an empty word file and protected it afterwards. The unprotected version of this file does not lead to a warning while the protected version does.
All files I’ve tested this on have been protected with Adobe Acrobat if that is important.

I’ve created a project to recreate this problem which uses Aspose.PDF version 23.3.0.

Empty-password-protected.pdf (32.0 KB) (password is 123456)
Empty.pdf (31.2 KB)

@JannikEsser

We have tested the case in our environment and could not notice the memory hike in case of both files. Regarding Rider, can you please share the steps to reproduce the same issue so that we can further investigate?

@asad.ali

I’ve found out, that this error only occurs with .NET 5 and downwards. From .NET 6 and upwards I couldn’t reproduce this memory hike either. I think this was a .NET problem and not directly resulting from your codebase.

So to reproduce this error the project must be created with .NET version 5 or lower. Then a password protected pdf file must be passed as a Stream to the provided function. This results in the memory spike.
As .NET 5 and lower are no longer supported I guess a fix for this won’t be possible. Is there a different solution for checking if a pdf file is password protected with aspose so we can avoid this problem?

@JannikEsser

We are afraid that no other option or way is present in the API in order to determine whether the file is password-protected. Nevertheless, it looks like that the issue is not particularly related to the Aspose.PDF. Please let us know if you still wish to use the API under .NET 5 or below? We will log an investigation ticket and share the ID with you.