記一次shm open返回EINVAL的錯誤排查

2022-05-12 14:29:19 字數 2232 閱讀 7675

看redis的bg資料拷貝的時候想起程序的資料是cow的,想寫個程式看看cow的細節,因為要用到訊號量操作sem_post和sem_wait,訊號量的建立依賴於共享記憶體物件shm_open,因為很久沒使用過的這個系統呼叫結果導致出了烏龍,把第乙個引數name給當成了路徑+名字,結果建立的時候返回的物件控制代碼是-1, errno被設定成了einval(無效引數)

int shm_open(const char *name, int oflag, mode_t mode);
b shm_open後打了乙個斷點進入shm_openni單步執行後, 發現shm_open先對name進行了處理,如果開頭為/的話會先開頭的所有/給乾掉,應該是不允許name中有這樣的特殊字元,這裡的name因為被我當成path+name了,所以會走這個地方, man中的手冊做建立的時候有時候也給name前加乙個/,但是加了和不加效果是一樣的。

然後程式繼續走,走著走著發現retq了,在中間找到了跳到retq的地方, 原來是shm_open+124中對name進行了檢查看看是否還存在特殊字元/,如果存在則設定errno後跳轉到retq

shm_open + 356中設定errno為einval,再繼續就是retq了

這裡有乙個很奇怪的點,上面判斷的shm_open+356將errno設定成了einval主要是通過0x16判斷得到,當然也可以通過errno的位址,後面標明了位址0x7ffff7dd3fb8,所以我們可以先列印errno的位址,然後再這段彙編裡面對比查詢一下,但是列印出來的結果卻和彙編中給出的位址不同,這個點沒有搞明白上stackoverflow提了個問題,這段彙編是沒問題的一定是給errno設定einval,

shm_open+356 到shm_open+365貌似也是不複雜,主要就三句**,於是耐心下來讀一讀

首先是將rip+0x202689這個作為乙個8位元組的位址,把這個位址對應的變數賦值給eax暫存器,但是列印出來的明明是0x7ffff7dd3fb1,但它的指在gdb中已經表明了是0x7ffff7dd3fb8,這是gdb中讓我很困惑的一點,其實rip暫存器永遠都是指向下一條要執行的指令,當我們把斷點打到這一行的時候,這一行**還沒有執行,執行的時候rip會被更新成下一行指令的位址,然後通過x /xg檢視位址0x7ffff7dd3fb8後發現是0xffffffffffffff60,這個值將被放進rax暫存器中

中間的更改ebx就不看了,看下一句怎麼把0x16放入errno中的,這句話的意思是將0x16放入到$fs + $rax的位址對應的8位元組記憶體空間中,\(rax和\)fs都能直接看到,但是$fs是作為段暫存器,gdb中顯示的雖然是0但使用fs暫存器的時候還會加上基址偏移是gdb沒有告訴我們的於是我們得拿到這個基址偏移, 這裡可以參照此處如果獲取fs暫存器基址, 簡單來說就是有乙個函式可以幫我們拿到,這個時候檢視被賦完得值確實是0x16,但是位址為什麼還是和&errno相等,就不填坑了

記一次除錯

這是我最近幾個月來遇到的最棘手的乙個問題 昨天花了4個小時找出第一層次的原因 這個糾結啊,本來和老婆說好準時下班回家吃飯的,結果被這個問題拖了老久。這是乙個gradle的plugin,用來resolve公司內部的dependency的,弄完了跑測試專案的,拋乙個npe,而且npe還不在自己的 裡面。...

記一次 EqualsAndHashCode的疑惑

lombok的使用真的是讓開發人員欲罷不能,乙個 data不管有多少屬性全部搞定,以後加字段也不用從新生成get和set方法。不過這裡還是有乙個小坑需要注意一下,舉個例子 public class equalsandhashcodetest data noargsconstructor access...

記一次除錯

這是我最近幾個月來遇到的最棘手的乙個問題 昨天花了4個小時找出第一層次的原因 這個糾結啊,本來和老婆說好準時下班回家吃飯的,結果被這個問題拖了老久。這是乙個gradle的plugin,用來resolve公司內部的dependency的,弄完了跑測試專案的,拋乙個npe,而且npe還不在自己的 裡面。...