没志青年
发布于 2025-10-10 / 20 阅读
0

调试技巧03 - 局部数组越界导致的问题

使用这个函数来模拟数组越界:

void buf_overflow(int n, char val)
{
    volatile char buf[5];
    volatile int a = 0x55;
    buf[0] = 0x5a;
    a++;
    buf[n] = val;
    myput_s_hex("buf[0] = ", buf[0]);
    myputs("\n");
    myput_s_hex("a is ", a);
    myputs("\n");
}

破坏其它变量

main 函数中调用:

buf_overflow(8, 'A');

    i.buf_overflow
    buf_overflow
        0x08001e3c:    b50e        ..      PUSH     {r1-r3,lr}   ; 只是为了分配空间,跟r1-3里面的值无关
        0x08001e3e:    225a        Z"      MOVS     r2,#0x5a
        0x08001e40:    f88d2000    ...     STRB     r2,[sp,#0]    ; 写入[0]
        0x08001e44:    2256        V"      MOVS     r2,#0x56
        0x08001e46:    9202        ..      STR      r2,[sp,#8]    ; 写入[8]
        0x08001e48:    f80d1000    ....    STRB     r1,[sp,r0]
        0x08001e4c:    f89d1000    ....    LDRB     r1,[sp,#0]
        0x08001e50:    a006        ..      ADR      r0,{pc}+0x1c ; 0x8001e6c
        0x08001e52:    f000f8df    ....    BL       myput_s_hex ; 0x8002014
        0x08001e56:    a008        ..      ADR      r0,{pc}+0x22 ; 0x8001e78
        0x08001e58:    f000f906    ....    BL       myputs ; 0x8002068
        0x08001e5c:    a007        ..      ADR      r0,{pc}+0x20 ; 0x8001e7c
        0x08001e5e:    9902        ..      LDR      r1,[sp,#8]
        0x08001e60:    f000f8d8    ....    BL       myput_s_hex ; 0x8002014
        0x08001e64:    a004        ..      ADR      r0,{pc}+0x14 ; 0x8001e78
        0x08001e66:    f000f8ff    ....    BL       myputs ; 0x8002068
        0x08001e6a:    bd0e        ..      POP      {r1-r3,pc}

破坏返回地址

buf_overflow(12, 'B');

索引变为了12,就会破坏返回地址。

1、打断点

2、根据 SP 查看内存

3、发现 LR 的值被修改了

08001F42

1000000000000001111101000010

bit 0 为 0,ARM指令,但是只cortex-m是thumb指令,程序崩溃,进入 HardFault_Handler 异常处理函数

不知道为什么keil调试器总是崩溃

上面的是从前往后推的,制作错误,看现象。

如果是看到了错误,怎么知道哪里出错呢?

1、出错时,查看硬件自动保存的栈帧

2、发生错误时,栈帧里面的PC是出现错误的语句

3、通过搜索,发现代码是存在的。但是毫不相关,莫名奇妙的,一个正确的函数为什么会出错。

这种问题后面解决

那如果是几数呢,就是bit0为1,这样找不到语句,还是会出错。

buf_overflow(12, 'A');

还有一种情况,凑巧了,跳转的语句是合法的地址,虽然能正常运行,但是项目的逻辑是错的。

可能出现循环。

如果那个值再大一点,破坏其他函数的栈,会更严重的破坏,导致程序在某个地方一直失败,但找不到原因。

两次打印结果不一样