我们的应用程序拥有数百万的用户,当我们尝试加载私有(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,另一个是从文件系统读取失败。

您应该在发布之前问我。

10-04 22:00
查看更多