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也不同。
先记录下来,以后留意一下。有懂的大佬请不吝赐教。
本文来自博客园,作者:moonのsun,转载请注明原文链接:https://www.cnblogs.com/moon-sun-blog/p/19141992

浙公网安备 33010602011771号