我们的应用程序拥有数百万的用户,当我们尝试加载私有(private)数据时遇到了一个严重的崩溃问题,因此在工作线程中,大约有0.01%的用户在System.load()期间崩溃。
记录如下:
608dd000-608de000 r--p 00000000 b3:07 8514 /data/data/com.UCMobile/com/core/version.0/lib/libWebCore_UC.so
Thread Name: '<unregistered>'
pid: 16879, tid: 16947 >>> com.UCMobile <<<
signal 7 (SIGBUS), code 2 (BUS_ADRERR), fault addr 61e3eb64
r0 61e3eb64 r1 00000000 r2 00000480 r3 c0000000
r4 00000000 r5 00000000 r6 00000000 r7 00000000
r8 000e7094 r9 00000005 10 6110a000 fp 0000006b
ip 00000000 sp 60bec8c8 lr 00000000 pc 40062698 cpsr a0000010
#00 pc 40062698 /system/bin/linker
#01 pc 40061ce0 /system/bin/linker
#02 pc 4005fc22 /system/bin/linker
#03 pc 40060172 /system/bin/linker
#04 pc 400614fe /system/bin/linker
#05 pc 0006755c /system/lib/libdvm.so
#06 pc 00091f68 /system/lib/libdvm.so
#07 pc 000273a0 /system/lib/libdvm.so
#08 pc 0002b2dc /system/lib/libdvm.so
#09 pc 00084e44 /system/lib/libdvm.so
#10 pc 00093f98 /system/lib/libdvm.so
#11 pc 000273a0 /system/lib/libdvm.so
#12 pc 0002b2dc /system/lib/libdvm.so
#13 pc 00084a94 /system/lib/libdvm.so
#14 pc 00084b20 /system/lib/libdvm.so
#15 pc 000700f8 /system/lib/libdvm.so
#16 pc 0000e4a4 /system/lib/libc.so
>>> [Dalvik stack info] <<<
at java.lang.Runtime.nativeLoad(Native Method)
at java.lang.Runtime.load(Runtime.java:339)
at java.lang.System.load(System.java:500)
当我们查看链接器的代码时,我们找出了导致应用崩溃的代码行:
http://androidxref.com/4.4.4_r1/xref/bionic/linker/linker_phdr.cpp#348
bool ElfReader::LoadSegments() {
347 if ((phdr->p_flags & PF_W) != 0 && PAGE_OFFSET(seg_file_end) > 0) {
348 memset((void*)seg_file_end, 0, PAGE_SIZE - PAGE_OFFSET(seg_file_end)); --> crash when memset
349 }
350
在大多数情况下,故障地址等于“seg_file_end”。 (我们可以通过
readelf -l libWebCore_UC.so
的信息进行验证。)如果一个用户像这样崩溃,他将一次又一次崩溃。 (某些用户崩溃了数百次。)
并且我们在加载so之前检查了它的大小,它的大小必须与我们期望的相同。
这些崩溃大多数是sigbus,有时是SIGSEGV。
有人对此有任何想法吗?
最佳答案
从Linux内核引用代码:
int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
int error;
struct file *file = vma->vm_file;
struct address_space *mapping = file->f_mapping;
struct file_ra_state *ra = &file->f_ra;
struct inode *inode = mapping->host;
pgoff_t offset = vmf->pgoff;
struct page *page;
loff_t size;
int ret = 0;
size = round_up(i_size_read(inode), PAGE_SIZE);
if (offset >= size >> PAGE_SHIFT)
return VM_FAULT_SIGBUS;
...
/* Things didn't work out. Return zero to tell the mm layer so. */
shrink_readahead_size_eio(file, ra);
return VM_FAULT_SIGBUS;
}
它有两种故障情况。其中之一是文件大小不足以覆盖vma,另一个是从文件系统读取失败。
您应该在发布之前问我。