Inzicht in de glibc-fout “corrupte grootte versus prev_size”

Ik heb een JNA-brug naar FDK-AAC geïmplementeerd. De broncode is hier

te vinden

Bij het benchmarken van mijn code kan ik honderden succesvolle runs op dezelfde invoer krijgen, en dan af en toe een C-level crash die het hele proces doodt, waardoor een core-dump wordt gegenereerd:

Als je naar de kerndump kijkt, ziet het er als volgt uit:

#1  0x00007f3e92e00f5d in __GI_abort () at abort.c:90
#2  0x00007f3e92e4928d in __libc_message ([email protected]=do_abort, [email protected]=0x7f3e92f70528 "*** Error in `%s': %s: 0x%s ***\n") at ../sysdeps/posix/libc_fatal.c:181
#3  0x00007f3e92e5064a in malloc_printerr (action=<optimized out>, str=0x7f3e92f6cdee "corrupted size vs. prev_size", ptr=<optimized out>, ar_ptr=<optimized out>) at malloc.c:5426
#4  0x00007f3e92e5304a in _int_free (av=0x7f3de0000020, p=<optimized out>, have_lock=0) at malloc.c:4337
#5  0x00007f3e92e5744e in __GI___libc_free (mem=<optimized out>) at malloc.c:3145
#6  0x00007f3e113921e9 in FDKfree (ptr=0x7f3de009df60) at libSYS/src/genericStds.cpp:233
#7  0x00007f3e1130d7d3 in Free_AacEncoder (p=0x7f3de0115740) at libAACenc/src/aacenc_lib.cpp:407
#8  0x00007f3e1130fbb3 in aacEncClose (phAacEncoder=0x7f3de0115740) at libAACenc/src/aacenc_lib.cpp:1395

Deze back/stack trace-fout is reproduceerbaar als ik de benchmark vaak genoeg herhaal, hoewel ik het moeilijk vind om te begrijpen wat de oorzaak van een dergelijke fout kan zijn? Geheugen toegewezen aan pointer 0x7f3de009df60wordt ook toegewezen binnen de CPP/C-code en ik kan garanderen dat dezelfde instantie die is toegewezen, wordt vrijgegeven. De benchmark is natuurlijk – single-threaded.

Na het lezen van deze:

veiligheidscontroles & amp; & amp;
interne functies

Ik ben nog steeds een harde tijd begrip – wat misschien wel een echte (niet-uitbuiting, maar eerder fout)) scenario dat me zorgt ervoor dat de bovenstaande fout te krijgen? en waarom gebeurt het zeer nauwelijks?

Huidige vermoeden

Het runnen van een gedetailleerde backtrace, krijg ik deze ingang:

#0  __GI_raise ([email protected]=6) at ../sysdeps/unix/sysv/linux/raise.c:51
        set = {__val = {4, 6378670679680, 645636045657660056, 90523359816, 139904561311072, 292199584, 139903730612120, 139903730611784, 139904561311088, 1460617926600, 47573685816, 4119199860131166208, 
            139904593745464, 139904553224483, 139904561311136, 288245657}}
        pid = <optimized out>
        tid = <optimized out>
#1  0x00007f3e92e00f5d in __GI_abort () at abort.c:90
        save_stage = 2
        act = {__sigaction_handler = {sa_handler = 0x7f3de026db10, sa_sigaction = 0x7f3de026db10}, sa_mask = {__val = {139903730540556, 19, 30064771092, 812522497172832284, 139903728706672, 1887866374039011357, 
              139900298780168, 3775732748407067896, 763430436865, 35180077121538, 4119199860131166208, 139904561311552, 139904553065676, 1, 139904561311584, 139904561312192}}, sa_flags = 4096, 
          sa_restorer = 0x14}
        sigs = {__val = {32, 0 <repeats 15 times>}}
#2  0x00007f3e92e4928d in __libc_message ([email protected]=do_abort, [email protected]=0x7f3e92f70528 "*** Error in `%s': %s: 0x%s ***\n") at ../sysdeps/posix/libc_fatal.c:181
        ap = {{gp_offset = 40, fp_offset = 32574, overflow_arg_area = 0x7f3e11adf1d0, reg_save_area = 0x7f3e11adf160}}
        fd = <optimized out>
        list = <optimized out>
        nlist = <optimized out>
        cp = <optimized out>
        written = <optimized out>
#3  0x00007f3e92e5064a in malloc_printerr (action=<optimized out>, str=0x7f3e92f6cdee "corrupted size vs. prev_size", ptr=<optimized out>, ar_ptr=<optimized out>) at malloc.c:5426
        buf = "00007f3de009e9f0"
        cp = <optimized out>
        ar_ptr = <optimized out>
        ptr = <optimized out>
        str = 0x7f3e92f6cdee "corrupted size vs. prev_size"
        action = <optimized out>
#4  0x00007f3e92e5304a in _int_free (av=0x7f3de0000020, p=<optimized out>, have_lock=0) at malloc.c:4337
        size = 2720
        fb = <optimized out>
        nextchunk = 0x7f3de009e9f0
        nextsize = 736
        nextinuse = <optimized out>
        prevsize = <optimized out>
        bck = <optimized out>
        fwd = <optimized out>
        errstr = 0x0
        locked = <optimized out>
#5  0x00007f3e92e5744e in __GI___libc_free (mem=<optimized out>) at malloc.c:3145
        ar_ptr = <optimized out>
        p = <optimized out>
        hook = <optimized out>
#6  0x00007f3e113921e9 in FDKfree (ptr=0x7f3de009df60) at libSYS/src/genericStds.cpp:233
No locals.
#7  0x00007f3e1130d7d3 in Free_AacEncoder (p=0x7f3de0115740) at libAACenc/src/aacenc_lib.cpp:407
No locals.
#8  0x00007f3e1130fbb3 in aacEncClose (phAacEncoder=0x7f3de0115740) at libAACenc/src/aacenc_lib.cpp:1395
        hAacEncoder = 0x7f3de009df60
        err = AACENC_OK
  • In frame #6zie je dat de aanwijzer in vragen 0x7f3de009df60is.
  • In frame #4kun je zien dat de grootte 2720 is, wat inderdaad de verwachte grootte is van de structuur die wordt vrijgegeven.
  • Het adres van nextchunkis echter 0x7f3de009e9f0, wat slechts 2704 bytes is na de huidige pointer die wordt vrijgegeven.
  • Ik kan bevestigen dat dit altijd het geval is wanneer de fout zich herhaalt.
  • Kan dit een sterke indicatie zijn van de fout die ik tegenkom ??

Antwoord 1, autoriteit 100%

OK, dus ik heb dit probleem kunnen oplossen.

Allereerst – Een praktische oorzaak voor “corrupte size vs. prev_size” is vrij eenvoudig: de besturingsstructuurvelden van de geheugenbrok in de aangrenzende volgende chunk worden overschreven vanwege toegang buiten het bereik van de code. als u xbytes toewijst voor pointer pmaar eindigt met schrijven voorbij xmet betrekking tot dezelfde pointer, kunt u deze fout krijgen, die de de huidige grootte van de geheugentoewijzing (chunk) is niet hetzelfde als wat wordt gevonden in de volgende chunk-besturingsstructuur (omdat deze wordt overschreven).

Wat de oorzaak van dit geheugenlek betreft: structuurtoewijzing in de Java/JNA-laag impliceerde een andere #pragma-gerelateerde opvulling/uitlijning dan waarmee dll/so was gecompileerd. Dit zorgde er op zijn beurt voor dat gegevens buiten de toegewezen structuurgrens werden geschreven. Door die uitlijning uit te schakelen, verdwenen de problemen. (Duizenden executies zonder een enkele crash!).

Other episodes