mmap + memcpy => SIGBUS ?

问题描述

代码库中存在类似的代码:

void *virt_addr = mmap(fd, flag, size0 offset);
void *temp = malloc(size0);
memcpy(temp, config, size1);
memcpy(virt_addr, temp, size0);
free(temp);
munmap(virt_addr, size);

我认为这里temp的申请和多进行一次memcpy没有必要,就改成了:

void *virt_addr = mmap(fd, flag, size, offset);
memcpy(virt_addr, config, size);
munmap(virt_addr, size);

看起来清爽很多,但是却出现了SIGBUS异常:

------------------------------------------------------------
SEGMENTATION FAULT DETECTED
------------------------------------------------------------
Signal:           7 (SIGBUS)
Signal Code:      1 (Address not mapped)
Fault Address:    0x0000ffff84010c28
Instruction Ptr:  0x0000ffff8696b230
Stack Pointer:    0x0000ffff8506de90
Frame Pointer:    0x0000ffff8506dea0
Process ID:       166
Thread ID:        171
Timestamp:        1970-01-01 00:01:07

Memory Context:
  Memory Mappings (around 0x0000ffff8c580c28):
     >> ffff8c580000-ffff8c590000 rw-s 00000000 [/dev/isp_vb] (FAULT ADDRESS HERE)
  Stack Information:
    Current stack pointer: 0x0000ffff8ddecacf
    Stack size limit: 8388608 byte (8192 KB)

额外的信息:

虚拟地址:pBaseAddress = 0xc0000000
物理地址:iommu_iova_to_phys 0xf0000000
offset和size:offset is 0x0, size is 0x10000

问题分析

从上面看,挂死的地址0x0000ffff8c580c28每次都相同,但是确实在映射范围内:ffff8c580000-ffff8c590000;肯定不是地址越界。

实际上我现在还不知道具体原因,搜了很多资料,都指向了字节对齐问题。
有一种说法,还没有得到验证:
memcpy处理设备内存的时候,有特殊要求,甚至说,memcpy最好不要用于设备内存;
memcpy(temp, config, size0)很安全,是因为temp是临时申请的堆上内存,虽然config对齐可能存在问题,但是memcpy仍旧可用;
memcpy(virt_addr, temp, size1),因为temp是符合要求的,所以memcpy也正常使用;
而:memcpy(virt_addr, config, size0),config对齐有问题,memcpy处理virt_addr又特殊,所以出现了物理内存总线访问错误(SIGBUS)。
亦或许和memcpy处理不同内存时的size要求有关?因为上述memcpy的size也不同。

先记录下来,以后留意一下。有懂的大佬请不吝赐教。

posted @ 2025-10-14 20:50  moonのsun  阅读(11)  评论(0)    收藏  举报