dart::bin::EventHandlerImplementation::EventHandlerEntry 崩溃分析

crash堆栈

1
2
3
4
Thread 31 name:  dart:io EventHandler
Thread 31 Crashed:
0 Flutter 0x000000010628adb0 dart::bin::EventHandlerImplementation::EventHandlerEntry (in Flutter) (eventhandler_macos.cc:375)
1 Flutter 0x000000010628ac1c dart::bin::EventHandlerImplementation::EventHandlerEntry (in Flutter) (eventhandler.h:91)

源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void EventHandlerImplementation::EventHandlerEntry(uword args) {
struct kevent events[kMaxEvents];
...
handler_impl->HandleEvents(events, result);
...
}

void EventHandlerImplementation::HandleEvents(struct kevent* events, int size) {
...
for (int i = 0; i < size; i++) {
// If flag EV_ERROR is set it indicates an error in kevent processing.
if ((events[i].flags & EV_ERROR) != 0) {
...
}
...
}
...
}

crash现场还原

1
2
3
4
0   Flutter                         0x000000010628adb0 dart::bin::EventHandlerImplementation::EventHandlerEntry (in Flutter) (eventhandler_macos.cc:375)

Binary Images:
0x105f8c000 - 0x106533fff Flutter arm64 <2e96fdadaf353b41b4ba6a8e63f06301> /private/var/containers/Bundle/Application/37D0CE9B-9F43-4034-ADF4-1B3C10A53419/LIKE.app/Frameworks/Flutter.framework/Flutter
  • 计算偏移量

0x000000010628adb0 - 0x105f8c000 = 3141040

  • 在xcode调试控制台 获取Flutter库的 载入地址

image list Flutter

1
2
(lldb) image list Flutter
[ 0] C7C1A8CC-055A-3747-8B7A-1B96E5D6FD4F 0x00000001000e0000 /Users/winnchen/Library/Developer/Xcode/DerivedData/BSUITestProject-adqfyjzmhqfposhenyppejsiglud/Build/Products/Debug-iphoneos/BSUITestProject.app/Flutter.framework/Flutter
  • 计算实际地址,设置断点

0x00000001000e0000 + 3141040 = 0x1003dedb0

1
breakpoint set -a 0x1003dedb0

分析寄存器与变量之间的对应关系

进入断点后,进行进一步的分析。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
loc_2fed24:
r20 = 0x0;
r25 = 0x0;
asm { sxtw x26, w21 };
r27 = stack[56];
goto loc_2fedb0;

loc_2fedb0:
#define EV_ERROR 0x4000 /* error, data contains errno */
if ((*(int8_t *)(r27 + 0xffffffffffffffff) & 0x40) != 0x0) goto loc_2ff80c;

loc_2feef0:
r20 = r20 + 0x1;
r27 = r27 + 0x20;
if (r20 < r26) goto loc_2fedb0;

从 crash 报告的保留 register 来看:

1
2
3
4
5
6
7
8
9
10
Thread 31 crashed with ARM-64 Thread State:
cpsr: 0x0000000060000000 fp: 0x0000000170e72ed0 lr: 0x000000010628ac1c pc: 0x000000010628adb0
sp: 0x0000000170e727d0 x0: 0x0000000000000000 x1: 0x0000000000000000 x10: 0x000000000000014c
x11: 0x00000001b0efad4c x12: 0x00000001b0efad4c x13: 0x000000000000007e x14: 0x0000000000000001
x15: 0x0000000000000881 x16: 0x0000000000000149 x17: 0x0000000000000000 x18: 0x0000000000000000
x19: 0x000000017066f600 x2: 0x0000000000000000 x20: 0x0000000000000000 x21: 0x0000000000000001
x22: 0x0000000000000000 x23: 0x0000000000001837 x24: 0x0000000000000000 x25: 0x0000000000000000
x26: 0x0000000000000001 x27: 0x0000000000000000 x28: 0x000000017066f634 x29: 0x0000000170e72ed0
x3: 0x0000000170e72860 x4: 0x0000000000000010 x5: 0x0000000000000000 x6: 0x0000000000000000
x7: 0x0000000000000000 x8: 0x0000000000000000 x9: 0x00000001ae9323a0
1
2
3
4
5
6
7
8
9
//大小为 0x20
struct kevent {
uintptr_t ident; /* identifier for this event */
int16_t filter; /* filter for event */
uint16_t flags; /* general flags */
uint32_t fflags; /* filter-specific flags */
intptr_t data; /* filter-specific data */
void *udata; /* opaque user data identifier */
};

r20 为循环变量 i 的值,此时为 0;r26为参数size的值,此时为 1;而r27则是代表 events + i的地址,从汇编也能看出来 r27 每次递增 0x20 ,正好是 struct kevent 的值,此时r27的值为 0。

也就是说传入的events参数为 NULL,而此处没有判空处理导致的崩溃。

events 参数为 NULL

由代码当中可以看出,传入 HandleEvents 的第一个参数是栈上的地址,不可能为空,此处是某种原因导致的栈上的数据被破坏,导致读出来的数据为 NULL 造成崩溃