![](/img/trans.png)
[英]Code which was built with g++7, crashes with access to unaligned memory
[英]what type of code can trigger unaligned data access sigbus trap dynamically?
我正在尋找有關未對齊數據訪問的SIGBUS。 我正在跟蹤此錯誤之一,我想知道這在西塔拉am335x上是如何發生的。 有人可以給我一個示例代碼來描述或確保觸發它。
添加代碼段:
int Read( void *value, uint32_t *size, const uint32_t baseAddress )
{
uint8_t *userDataAddress = (uint8_t *)( baseAddress + sizeof( DBANode ));
memcpy( value, userDataAddress, ourDataSize );
*size = ourDataSize;
return 0;
}
DBA節點是一個20字節的類對象。 baseAddress再次是對共享內存文件的mmap,它是強制轉換為uint32_t的DBANode類對象類型的,因此可以執行該算法。
這是本節的重點:
91a8: e51b3010 ldr r3, [fp, #-16]
91ac: e5933000 ldr r3, [r3]
91b0: e51b0014 ldr r0, [fp, #-20] ; 0xffffffec
91b4: e51b1008 ldr r1, [fp, #-8]
91b8: e1a02003 mov r2, r3
91bc: ebffe72b bl 2e70 <memcpy@plt>
91c0: e51b3010 ldr r3, [fp, #-16]
91c4: e5932000 ldr r2, [r3]
91c8: e51b3018 ldr r3, [fp, #-24] ; 0xffffffe8
91cc: e5832000 str r2, [r3]
00002e70 <memcpy@plt>:
2e70: e28fc600 add ip, pc, #0, 12
2e74: e28cca08 add ip, ip, #8, 20 ; 0x8000
2e78: e5bcf868 ldr pc, [ip, #2152]! ; 0x868
當重建完全相同的代碼庫時,問題就消失了。 gcc可以使用為gcc指定的-O0相同的優化來創建2個不同版本的指令嗎?
我還比較了庫,以便在兩個編譯中都將文件obj轉儲。 他們是完全一樣的。 該API經常使用。 但是,崩潰只有在長時間使用后才會發生。 我每500毫秒讀取一次相同的節點。 因此,這是不一致的。 我應該看看指針損壞嗎?
從Cortex-A8技術參考手冊中:
處理器支持未對齊字和半字的加載和存儲。 處理器進行所需數量的內存訪問,並透明地傳輸相鄰字節。
注意跨越單詞邊界的數據訪問可能會增加訪問時間。
將CP15 c1控制寄存器中的A位置1可啟用對齊檢查。 當A位設置為1時,兩種類型的存儲器訪問會產生數據中止信號和對齊故障狀態代碼:
不是半字對齊的16位訪問
未對齊的32位加載或存儲
對齊錯誤檢測是強制性的地址生成功能,而不是外部內存管理硬件的可選支持功能。有關未對齊數據訪問支持的更多信息,請參見《 ARM體系結構參考手冊 》。
如果未與傳輸大小對齊,則從ARM ARM發出總是會產生對齊錯誤的指令:LDREX,STREX,LDREXD,STREXD,LDM,STM,LDRD,RFE,SRS,STRD,SWP,LDC,LDC2,STC,STC2, VLDM,VLDR,VPOP,VPUSH,VSTM,VSTR
另外,大多數PUSH,POP和VLDx都指定了:align:。
進一步,
在包含虛擬化擴展的實現中,對設備或強序內存的未對齊訪問總是會導致對齊錯誤數據中止異常
就像在鏈接的問題中一樣,結構是導致“預期的”未對齊訪問的最明顯方法,但是堆棧指針或其他變量指針的任何損壞也將產生相同的結果。 根據內核的配置方式,會影響正常的單個字/半字訪問速度是否緩慢還是觸發故障。
如果您有權訪問ETM跟蹤,則可以識別確切的訪問。 似乎該零件具有ETM / ETB(因此不需要花哨的跟蹤捕獲設備),但我不知道獲得使用工具的容易程度。
至於什么代碼可以觸發此問題,是的,甚至memcpy()
都可能是個問題 。 由於ARM指令集具有用於傳輸多個寄存器(或AA64中的寄存器對)的優化,因此優化的庫函數將更喜歡“流式傳輸”數據,而不是逐字節地進行加載和存儲。 根據數據結構和編譯目標,完全有可能以非法的LDM結束未對齊的地址。
原來baseAddress是問題所在。 正如我所提到的,它是到mmap可能失敗的共享內存位置的mmap。 失敗的mmap返回-1,並且代碼正在檢查NULL並繼續寫入-1,即0xFFFFFFFF導致sigbus。 使用memcpy時會看到代碼1。 嘗試任何其他訪問方式(如直接字節尋址)都會使sigbus出現代碼3。
我仍然不確定為什么它會觸發SIGBUS而不是SIGSEGV。 難道這不應該是內存沖突嗎? 這是一個例子:
int main(int argc, char **argv)
{
// Shared memory example
const char *NAME = "SharedMemory";
const int SIZE = 10 * sizeof(uint8_t);
uint8_t src[]={0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0x00};
int shm_fd = -1;
shm_fd = shm_open(NAME, O_CREAT | O_RDONLY, 0666);
ftruncate(shm_fd, SIZE);
// Map shared memory segment to address space
uint8_t *ptr = (uint8_t *) mmap(0, SIZE, PROT_READ | PROT_WRITE | _NOCACHE, MAP_SHARED, shm_fd, 0);
if(ptr == MAP_FAILED)
{
std::cerr << "ERROR in mmap()" << std::endl;
// return -1;
}
printf("ptr = 0x%08x\n",ptr);
std::cout << "Now storing data to mmap() memory" << std::endl;
#if 0
ptr[0] = 0x11;
ptr[1] = 0x22;
ptr[2] = 0x33;
ptr[3] = 0x44;
ptr[4] = 0x55;
ptr[5] = 0x66;
ptr[6] = 0x77;
ptr[7] = 0x88;
ptr[8] = 0x99;
ptr[9] = 0x00;
#endif
memcpy(ptr,src,SIZE); //causes sigbus code 1
shm_unlink(NAME);
}
我仍然不知道為什么mmap不能在shm上失敗,即使我有100MB的可用RAM,並且我的所有資源限制都設置為無限制,而1000 fds限制中仍然有超過400 fds(文件描述符)可用。 !
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.