FC3000

解決eduke32詭異的crash問題


Crash Log

Thread 1 "eduke32" received signal SIGSEGV, Segmentation fault.
0xb6e25e68 in memset () from /lib//libc.so.0
(gdb) bt
#0  0xb6e25e68 in memset () from /lib//libc.so.0
#1  0x001e1e68 in decodeframe (
    srcP=0xb4df2bc6 "((\v\v\026!\342Ƴ\001\263\263\263\001\263\001\361\241_,,\017`\032\032!\026(",
    dstP=0x1d229bb <error: Cannot access memory at address 0x1d229bb>)
    at source/jmact/animlib.c:180
#2  0x001e212c in renderframe (framenumber=0, pagepointer=0xb4df0b78)
    at source/jmact/animlib.c:239
#3  0x001e2198 in drawframe (framenumber=0) at source/jmact/animlib.c:253
#4  0x001e2a98 in ANIM_DrawFrame (framenumber=1) at source/jmact/animlib.c:330
#5  0x000cf2d0 in G_PlayAnim (fn=0x26a658 "logo.anm", t=5 '\005')
    at source/anim.c:261
#6  0x0006bccc in G_DisplayLogo () at source/game.c:8668
#7  0x0007055c in app_main (argc=1, argv=0xbeedbdf4) at source/game.c:9960
#8  0x00250f20 in main (argc=1, argv=0xbeedbdf4) at src/sdlayer.c:208

Crash位置在第11行

static void decodeframe(uint8_t * srcP, uint8_t * dstP)
{
    do
    {
        int32_t count=*srcP++;

        if (!count) /* Short RLE */
        {
            int32_t color = *(srcP+1);
            count = *(uint8_t *)((srcP += sizeof(int16_t)) - sizeof(int16_t));
            Bmemset((dstP += count) - count, color, count);
            continue;
        }
        else if ((count & 0x80) == 0) /* Short copy */
        {
            Bmemcpy((dstP += count) - count, (srcP += count) - count, count);
            continue;
        }
        else if ((count &= ~0x80) > 0) /* short skip */
        {
            dstP += count;
            continue;
        }

        /* long op */
        count = B_LITTLE16(*((uint16_t *)((srcP += sizeof(int16_t)) - sizeof(int16_t))));

        if (!count) /* stop sign */
            return;
        else if ((count & 0x8000) == 0) /* long skip */
        {
            dstP += count;
            continue;
        }
        else if ((count &= ~0x8000) & 0x4000) /* long RLE */
        {
            int32_t color = *srcP++;
            count &= ~0x4000;
            Bmemset((dstP += count) - count, color, count);
            continue;
        }

        /* long copy */
        Bmemcpy((dstP += count) - count, (srcP += count) - count, count);
    }
    while (1);
}

但是仔細追查後,發現有問題是這行

count = B_LITTLE16(*((uint16_t *)((srcP += sizeof(int16_t)) - sizeof(int16_t))));

改寫比較容易看懂的程式

count = B_LITTLE16(*(uint16_t *)srcP);
srcP += sizeof(int16_t);

GDB看了一下

count = B_LITTLE16(*((uint16_t *)((srcP += sizeof(int16_t)) - sizeof(int16_t))));

(gdb) p/x count
$2 = 0x9d80

(gdb) x/16x srcP-4
0xb4dc9b81:     0x8000  0xd99d  0x0000  0x2605  0x2d80  0x00c1  0x2605  0x2826
0xb4dc9b91:     0x280b  0x0600  0x0b0b  0x0b16  0x1a16  0x1a0b  0x0b1a  0x0b1a

srcP的位址是0xb4dc9b83,所以*(uint_16_t*)srcP應該是拿到0xd99d,但是結果竟然是0x9d80

司徒也不知道為何LDRH是取低位址的值(0xb4dc9b83 ~ 0xb4dc9b82),而不是高位址的值(0xb4dc9b84 ~ 0xb4dc9b83)

(gdb) stepi
   0x001e1f08 <+304>:   sub     r3, r3, #2
=> 0x001e1f0c <+308>:   ldrh    r3, [r3]
   0x001e1f10 <+312>:   str     r3, [r11, #-8]
   0x001e1f14 <+316>:   ldr     r3, [r11, #-8]

(gdb) info r
r3             0xb4dc9b83       3034356611

(gdb) stepi
   0x001e1f08 <+304>:   sub     r3, r3, #2
   0x001e1f0c <+308>:   ldrh    r3, [r3]
=> 0x001e1f10 <+312>:   str     r3, [r11, #-8]
   0x001e1f14 <+316>:   ldr     r3, [r11, #-8]

(gdb) info r
r3             0x9d80   40320

因此,使用一個workaround的方式修掉

//count = B_LITTLE16(*((uint16_t *)((srcP += sizeof(int16_t)) - sizeof(int16_t))));
count = B_LITTLE16(srcP[0] + (((uint16_t)srcP[1]) << 8));
srcP += sizeof(int16_t);


返回上一頁