Menu

#207 Djvups fails to convert document: heap corruption

djvulibre
closed
nobody
msvc2010 (1)
5
2013-03-30
2012-12-15
No

Test program "djvups" on windows fails to run properly.
It reports on heap corruption after some time of converting the big document of more than 200 pages.
OS: Windows 7 x64
Compiler: msvc2010

Discussion

  • Mantosh Kumar

    Mantosh Kumar - 2013-02-17

    Hi All,

    I was able to recreate #207 issue on my machine. I have used the input document which had 665 pages. I ran the "djvups" application with full page heap enabled. I also did some analysis which might be helpful to resolve this issue.

    ========> embedded my comment for better understanding.

    Analysis

    0:000> g
    (1a44.14dc): Access violation - code c0000005 (first chance)
    First chance exceptions are reported before any exception handling.
    This exception may be expected and handled.
    eax=00000001 ebx=0b6b2fe4 ecx=773d389a edx=00a61078 esi=0e26dff0 edi=0e25bfe0
    eip=63dfc0a4 esp=42d5f5c4 ebp=42d5f664 iopl=0 nv up ei pl nz ac po nc
    cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010212
    libdjvulibre!DJVU::DjVuFileCache::clear_to_size+0x2e4:
    63dfc0a4 c7471800000000 mov dword ptr [edi+18h],0 ds:002b:0e25bff8=????????

    =======> $ebx(0b6b2fe4) seems to have address which is from heap
    =======> segment.This is the place where AV occurs while "djvups" was
    =======> with full page heap enabled.

    =======> Below is the faulty call stack where actual corruption seems to
    =======> be happening.
    0:002> kB
    ChildEBP RetAddr Args to Child
    42d5f664 63dfbc9d 0b6b2fb0 009fcc1f b6c18267 libdjvulibre!DJVU::DjVuFileCache::clear_to_size+0x2e4 [c:\codelocation\djvulibre-3.5.25\libdjvu\djvufilecache.cpp @ 181]
    42d5f6bc 63de9ae9 0b6b2fb0 42d5f7a4 b6c1820b libdjvulibre!DJVU::DjVuFileCache::add_file+0x17d [c:\codelocation\djvulibre-3.5.25\libdjvu\djvufilecache.cpp @ 141]
    42d5f74c 63de9ba4 0b6b2fb0 b6c18353 0b53ce48 libdjvulibre!DJVU::add_to_cache+0x69 [c:\codelocation\djvulibre-3.5.25\libdjvu\djvudocument.cpp @ 1393]
    42d5f788 63de9c39 42d5f7a4 b6c18343 41d02e00 libdjvulibre!DJVU::DjVuDocument::add_to_cache+0x74 [c:\codelocation\djvulibre-3.5.25\libdjvu\djvudocument.cpp @ 1405]
    42d5f7b8 63e0f070 41d02e00 00000042 00000001 libdjvulibre!DJVU::DjVuDocument::notify_file_flags_changed+0x69 [c:\codelocation\djvulibre-3.5.25\libdjvu\djvudocument.cpp @ 1419]
    42d5f80c 63df0491 41d02e00 00000042 00000001 libdjvulibre!DJVU::DjVuPortcaster::notify_file_flags_changed+0x80 [c:\codelocation\djvulibre-3.5.25\libdjvu\djvuport.cpp @ 585]
    42d5f900 63deff75 b6c18df7 00000000 00000000 libdjvulibre!DJVU::DjVuFile::decode_func+0x4c1 [c:\codelocation\djvulibre-3.5.25\libdjvu\djvufile.cpp @ 542]
    42d5f92c 63e36e62 41d02e00 b6c18db7 00000000 libdjvulibre!DJVU::DjVuFile::static_decode_func+0xb5 [c:\codelocation\djvulibre-3.5.25\libdjvu\djvufile.cpp @ 467]
    42d5f96c 7125c556 428a6ff0 b6c18d6d 00000000 libdjvulibre!DJVU::start+0x42 [c:\codelocation\djvulibre-3.5.25\libdjvu\gthreads.cpp @ 143]
    42d5f9a4 7125c600 00000000 42d5f9bc 74f833aa MSVCR100!_endthreadex+0x3f
    42d5f9b0 74f833aa 428a4de8 42d5f9fc 773d9ef2 MSVCR100!_endthreadex+0xce
    42d5f9bc 773d9ef2 428a4de8 35ae4ed9 00000000 kernel32!BaseThreadInitThunk+0xe
    42d5f9fc 773d9ec5 7125c59c 428a4de8 00000000 ntdll!__RtlUserThreadStart+0x70
    42d5fa14 00000000 7125c59c 428a4de8 00000000 ntdll!_RtlUserThreadStart+0x1b

    =======> The faulty source line where AV occurred.
    void DjVuFileCache::clear_to_size(int size)
    {
    list.del(item->list_pos);
    }

    ========> From above call stack,we can get the base address of the
    ========> HEAP chunk.So we need to go (0x20 = 32byte) backward to get
    ========> the metadata information of this chunk.

    0:002> dd 0b6b2fb0-0x20
    0b6b2f90 abcdbbbb 00a61000 00000050 00001000 ====>header information
    0b6b2fa0 00000000 00000000 0463a04c dcbabbbb
    0b6b2fb0 63e76560 00000001 00000001 ffffffff ====>start of chunk
    0b6b2fc0 000014dc 05933fe0 fffffffe 00000001
    0b6b2fd0 000014dc 00000000 00000000 00000000
    0b6b2fe0 00000000 63e75a9c 00000188 0e536ff0
    0b6b2ff0 42644ff0 c0c0c001 00a00000 009e6d62
    ======> The last two entry should contain the d0d0d0d0 which is
    ======> suffix pattern for the chunk when full page heap is enabled.
    ======> So this heap corruption seems to be the category of suffix
    ======> pattern corruption.
    0b6b3000 ???????? ???????? ???????? ????????
    ====> inaccessible page start address(0b6b3000) at the end of the chunk.

    ======> dump the meta data information for this address.
    0:002> dt _DPH_BLOCK_INFORMATION 0b6b2fb0-0x20
    ntdll!_DPH_BLOCK_INFORMATION
    +0x000 StartStamp : 0xabcdbbbb ===>start signature(full page)
    +0x004 Heap : 0x00a61000 Void
    +0x008 RequestedSize : 0x50 ====>actual size(0x50=80byte)
    +0x00c ActualSize : 0x1000
    +0x010 FreeQueue : _LIST_ENTRY [ 0x0 - 0x0 ]
    +0x010 FreePushList : _SINGLE_LIST_ENTRY
    +0x010 TraceIndex : 0
    +0x018 StackTrace : 0x0463a04c Void ===>stack trace information
    +0x01c EndStamp : 0xdcbabbbb ====> end signature(full page)

    ======> Now dump the stracktrace address to get the call stack where
    ======> this chunk was allocated from the HEAP.
    0:002> dds 0x0463a04c
    0463a04c 00000000
    0463a050 00006001
    0463a054 000d0043
    0463a058 68458e89 verifier!AVrfDebugPageHeapAllocate+0x229
    0463a05c 77470d06 ntdll!RtlDebugAllocateHeap+0x30
    0463a060 7742ae7e ntdll!RtlpAllocateHeap+0xc4
    0463a064 773d3cee ntdll!RtlAllocateHeap+0x23a
    0463a068 71210269 MSVCR100!malloc+0x4b
    0463a06c 7121233b MSVCR100!operator new+0x1f
    0463a070 63db48c3 libdjvulibre!DJVU::DjVuFileCache::create+0x13 [c:\codelocation\djvulibre-3.5.25\libdjvu\djvufilecache.h @ 280]
    0463a074 63db69d5 libdjvulibre!ddjvu_context_create+0xa5 [c:\codelocation\djvulibre-3.5.25\libdjvu\ddjvuapi.cpp @ 376]
    0463a078 00e1146f djvups!main+0xff [c:\codelocation\djvulibre-3.5.25\tools\djvups.cpp @ 254]
    0463a07c 00e117f0 djvups!tmainCRTStartup+0x122 [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c @ 555]
    0463a080 74f833aa kernel32!BaseThreadInitThunk+0xe
    0463a084 773d9ef2 ntdll!
    RtlUserThreadStart+0x70
    0463a088 773d9ec5 ntdll!_RtlUserThreadStart+0x1b

    Conclusion and Resolution

    From the above analysis, it can be concluded that, this is suffix pattern type corruption and hence i suspect that this bug might be of some variance of "Off-by-one" error which is happening in very rare scenario when input document is having many pages.

    I think there is some problem in passing the argument to "clear_to_size" call,which later manifest into AV due to heap corruption.

    void
    DjVuFileCache::add_file(const GP<DjVuFile> & file)
    {
    if (_max_size>=0) clear_to_size(_max_size-add_size);
    }

    So i believe, this piece of code should be reviewed carefully to fix this bug.

    Hopefully the above discussion would help us to quickly fix this heap corruption scenario.

    Please let me know you all thoughts.

    Regards,
    Mantosh Kumar, India
    email:mantosh4u@gmail.com

     

    Last edit: Mantosh Kumar 2013-02-17
  • Mantosh Kumar

    Mantosh Kumar - 2013-02-17

    Hi All,

    I was able to recreate #207 issue on my machine. I have used the input document which had 665 pages. I ran the "djvups" application with full page heap enabled. I also did some analysis which might be helpful to resolve this issue.

    ========> embedded my comment for better understanding.

    Analysis

    0:000> g
    (1a44.14dc): Access violation - code c0000005 (first chance)
    First chance exceptions are reported before any exception handling.
    This exception may be expected and handled.
    eax=00000001 ebx=0b6b2fe4 ecx=773d389a edx=00a61078 esi=0e26dff0 edi=0e25bfe0
    eip=63dfc0a4 esp=42d5f5c4 ebp=42d5f664 iopl=0 nv up ei pl nz ac po nc
    cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010212
    libdjvulibre!DJVU::DjVuFileCache::clear_to_size+0x2e4:
    63dfc0a4 c7471800000000 mov dword ptr [edi+18h],0 ds:002b:0e25bff8=????????

    =======> $ebx(0b6b2fe4) seems to have address which is from heap =======> segment.This is the place where AV occurs while "djvups" was
    =======> with full page heap enabled.

    =======> Below is the faulty call stack where actual corruption seems to
    =======> be happening.
    0:002> kB
    ChildEBP RetAddr Args to Child
    42d5f664 63dfbc9d 0b6b2fb0 009fcc1f b6c18267 libdjvulibre!DJVU::DjVuFileCache::clear_to_size+0x2e4 [c:\codelocation\djvulibre-3.5.25\libdjvu\djvufilecache.cpp @ 181]
    42d5f6bc 63de9ae9 0b6b2fb0 42d5f7a4 b6c1820b libdjvulibre!DJVU::DjVuFileCache::add_file+0x17d [c:\codelocation\djvulibre-3.5.25\libdjvu\djvufilecache.cpp @ 141]
    42d5f74c 63de9ba4 0b6b2fb0 b6c18353 0b53ce48 libdjvulibre!DJVU::add_to_cache+0x69 [c:\codelocation\djvulibre-3.5.25\libdjvu\djvudocument.cpp @ 1393]
    42d5f788 63de9c39 42d5f7a4 b6c18343 41d02e00 libdjvulibre!DJVU::DjVuDocument::add_to_cache+0x74 [c:\codelocation\djvulibre-3.5.25\libdjvu\djvudocument.cpp @ 1405]
    42d5f7b8 63e0f070 41d02e00 00000042 00000001 libdjvulibre!DJVU::DjVuDocument::notify_file_flags_changed+0x69 [c:\codelocation\djvulibre-3.5.25\libdjvu\djvudocument.cpp @ 1419]
    42d5f80c 63df0491 41d02e00 00000042 00000001 libdjvulibre!DJVU::DjVuPortcaster::notify_file_flags_changed+0x80 [c:\codelocation\djvulibre-3.5.25\libdjvu\djvuport.cpp @ 585]
    42d5f900 63deff75 b6c18df7 00000000 00000000 libdjvulibre!DJVU::DjVuFile::decode_func+0x4c1 [c:\codelocation\djvulibre-3.5.25\libdjvu\djvufile.cpp @ 542]
    42d5f92c 63e36e62 41d02e00 b6c18db7 00000000 libdjvulibre!DJVU::DjVuFile::static_decode_func+0xb5 [c:\codelocation\djvulibre-3.5.25\libdjvu\djvufile.cpp @ 467]
    42d5f96c 7125c556 428a6ff0 b6c18d6d 00000000 libdjvulibre!DJVU::start+0x42 [c:\codelocation\djvulibre-3.5.25\libdjvu\gthreads.cpp @ 143]
    42d5f9a4 7125c600 00000000 42d5f9bc 74f833aa MSVCR100!_endthreadex+0x3f
    42d5f9b0 74f833aa 428a4de8 42d5f9fc 773d9ef2 MSVCR100!_endthreadex+0xce
    42d5f9bc 773d9ef2 428a4de8 35ae4ed9 00000000 kernel32!BaseThreadInitThunk+0xe
    42d5f9fc 773d9ec5 7125c59c 428a4de8 00000000 ntdll!__RtlUserThreadStart+0x70
    42d5fa14 00000000 7125c59c 428a4de8 00000000 ntdll!_RtlUserThreadStart+0x1b

    =======> The faulty source line where AV occurred.
    void DjVuFileCache::clear_to_size(int size)
    {
    list.del(item->list_pos);
    }

    ========> From above call stack,we can get the base address of the
    ========> HEAP chunk.So we need to go (0x20 = 32byte) backward to get
    ========> the metadata information of this chunk.

    0:002> dd 0b6b2fb0-0x20
    0b6b2f90 abcdbbbb 00a61000 00000050 00001000 ====>header information
    0b6b2fa0 00000000 00000000 0463a04c dcbabbbb
    0b6b2fb0 63e76560 00000001 00000001 ffffffff ====>start of chunk
    0b6b2fc0 000014dc 05933fe0 fffffffe 00000001
    0b6b2fd0 000014dc 00000000 00000000 00000000
    0b6b2fe0 00000000 63e75a9c 00000188 0e536ff0
    0b6b2ff0 42644ff0 c0c0c001 00a00000 009e6d62
    ======> The last two entry should contain the d0d0d0d0 which is
    ======> suffix pattern for the chunk when full page heap is enabled.
    ======> So this heap corruption seems to be the category of suffix
    ======> pattern corruption.
    0b6b3000 ???????? ???????? ???????? ????????
    ====> inaccessible page start address(0b6b3000) at the end of the chunk.

    ======> dump the meta data information for this address.
    0:002> dt _DPH_BLOCK_INFORMATION 0b6b2fb0-0x20
    ntdll!_DPH_BLOCK_INFORMATION
    +0x000 StartStamp : 0xabcdbbbb ===>start signature(full page)
    +0x004 Heap : 0x00a61000 Void
    +0x008 RequestedSize : 0x50 ====>actual size(0x50=80byte)
    +0x00c ActualSize : 0x1000
    +0x010 FreeQueue : _LIST_ENTRY [ 0x0 - 0x0 ]
    +0x010 FreePushList : _SINGLE_LIST_ENTRY
    +0x010 TraceIndex : 0
    +0x018 StackTrace : 0x0463a04c Void ===>stack trace information
    +0x01c EndStamp : 0xdcbabbbb ====> end signature(full page)

    ======> Now dump the stracktrace address to get the call stack where
    ======> this chunk was allocated from the HEAP.
    0:002> dds 0x0463a04c
    0463a04c 00000000
    0463a050 00006001
    0463a054 000d0043
    0463a058 68458e89 verifier!AVrfDebugPageHeapAllocate+0x229
    0463a05c 77470d06 ntdll!RtlDebugAllocateHeap+0x30
    0463a060 7742ae7e ntdll!RtlpAllocateHeap+0xc4
    0463a064 773d3cee ntdll!RtlAllocateHeap+0x23a
    0463a068 71210269 MSVCR100!malloc+0x4b
    0463a06c 7121233b MSVCR100!operator new+0x1f
    0463a070 63db48c3 libdjvulibre!DJVU::DjVuFileCache::create+0x13 [c:\codelocation\djvulibre-3.5.25\libdjvu\djvufilecache.h @ 280]
    0463a074 63db69d5 libdjvulibre!ddjvu_context_create+0xa5 [c:\codelocation\djvulibre-3.5.25\libdjvu\ddjvuapi.cpp @ 376]
    0463a078 00e1146f djvups!main+0xff [c:\codelocation\djvulibre-3.5.25\tools\djvups.cpp @ 254]
    0463a07c 00e117f0 djvups!tmainCRTStartup+0x122 [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c @ 555]
    0463a080 74f833aa kernel32!BaseThreadInitThunk+0xe
    0463a084 773d9ef2 ntdll!
    RtlUserThreadStart+0x70
    0463a088 773d9ec5 ntdll!_RtlUserThreadStart+0x1b

    Conclusion and Resolution

    From the above analysis, it can be concluded that, this is suffix pattern type corruption and hence i suspect that this bug might be of some variance of "Off-by-one" error which is happening in very rare scenario when input document is having many pages.

    I think there is some problem in passing the argument to "clear_to_size" call,which later manifest into AV due to heap corruption.

    void
    DjVuFileCache::add_file(const GP<DjVuFile> & file)
    {
    if (_max_size>=0) clear_to_size(_max_size-add_size);
    }

    So i believe, this piece of code should be reviewed carefully to fix this bug.

    Hopefully the above discussion would help us to quickly fix this heap corruption scenario.

    Please let me know you all thoughts.

    Regards,
    Mantosh Kumar, India
    email:mantosh4u@gmail.com

     
  • Leon Bottou

    Leon Bottou - 2013-03-30

    This was useful.
    I believe my last patch in the djvulibre-git fixes this.
    - L.

     
  • Leon Bottou

    Leon Bottou - 2013-03-30
    • status: open --> closed
     

Log in to post a comment.