亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

調用 Syscall 函數時出現異常

調用 Syscall 函數時出現異常

Go
炎炎設計 2023-06-26 17:18:32
我正在使用 Go 的系統調用包來調用用 C++ 編寫的 DLL。C++ 方法簽名如下所示。init(int* buffer, int argc, char* argv[], const char* fileName, const char* key, const char* prefix, const char* version)這是我用來在 Go 中調用上述方法的函數。func init(  buffer uintptr,   argsCount int,   args []string,   fileName string,   key string,   prefix string,   version string) uintptr {    // libHandle is handle to the loaded DLL    methodAddress := getProcAddress(libHandle, "init")    status, _, err := syscall.Syscall9(      methodAddress,      7,      buffer,      uintptr(unsafe.Pointer(&argsCount)),      uintptr(unsafe.Pointer(&args)),      uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(fileName))),      uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(key))),      uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(prefix))),      uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(version))),      0,      0)      fmt.Println(err.Error())      return status }當我調用此方法并且對此沒有任何想法時,我收到此錯誤。Exception 0xc0000005 0x0 0x0 0x7fffe30bdb33PC=0x7fffe30bdb33syscall.Syscall9(0x7fffe32db600, 0x7, 0x97db50, 0xc00007ff10, 0xc00007ff70, 0xc000054180, 0xc0000541a0, 0xc0000541c0, 0xc0000541e0, 0x0, ...)c:/go/src/runtime/syscall_windows.go:210 +0xf3main.main() E:/Path/test.go:157 +0x2be rax     0x81fbf0 rbx     0x1 rcx     0x7ff804ad1310 rdi     0x7ff10 rsi     0xc00007ff70 rbp     0x0 rsp     0x81fbc0 r8      0x0 r9      0x7ff804ad0000 r10     0xc00007ff00 r11     0x81fbf0 r12     0x7ff10 r13     0xc00007ff70 r14     0xc000054180 r15     0x97db50 rip     0x7fffe30bdb33 rflags  0x10257 cs      0x33 fs      0x53 gs      0x2b
查看完整描述

1 回答

?
小唯快跑啊

TA貢獻1863條經驗 獲得超2個贊

那個設定

所以,基本上,你得到的映射是

  1. int* buffer?→?buffer uintptr

  2. int argc→?unsafe.Pointer(&argsCount),其中&argsCount是一個指向int

  3. char* argv[]→?unsafe.Pointer(&args),哪里args[]string

  4. const char* fileNameunsafe.Pointer(syscall.StringToUTF16Ptr(fileName))

    const char* key,?const char* prefix,?const char* version— 同上。

存在的問題

現在這有什么問題呢。

  1. uintptr禁止在函數之間傳遞包含活動 Go 對象地址的值。(稍后會詳細介紹。)

  2. argsCount您將函數參數的地址傳遞給argc。如果將其解釋為計數,則典型的商品平臺/操作系統(例如 amd64/Windows)上的地址是一個極其巨大的值。

    我敢打賭,當函數嘗試從中讀取這么多元素時,它會崩潰,導致argv它讀取進程未映射的內存。

  3. 這里有兩個問題:

    1. 將切片值的地址作為參數傳遞,期望該切片的第一個元素的地址是錯誤的。

      這是因為切片值(目前,在您應該使用的“參考”Go 實現中)是具有struct3 個字段的:底層數據數組的地址、該數組中允許使用的元素數以及總數該數組中此類元素的計數append,在對切片值調用時,函數可以使用這些元素,而無需重新分配。

      當您擁有args []string并執行時&args,您將獲得該結構的地址,而不是該切片的第一個元素的地址。

      要執行后者,請使用&args[0].

    2. 在 Go 中,字符串(通常是這樣,我們假設是這樣)包含編碼為 UTF-8 的字符。這通常不是 Windows 本機 C++ 代碼在表示需要char *.

      我猜,你需要首先為 構建一個合適的東西argv,比如

      argv?:=?make([]unsafe.Pointer,?0,?len(args))for?i,?s?:=?range?args?{
      ????argv[i]?=?unsafe.Pointer(syscall.StringToUTF16Ptr(s))
      }

      然后傳遞&argv[0]給被調用者。

      但請參閱下文syscall.StringToUTF16Ptr()

  4. 您正在做的將字符串數據傳遞給具有該類型的其余參數的準備工作const char*似乎是正確的,但前提是被調用者確實意味著它char是一個 16 位整數。

    換句話說,用于編譯該庫的源代碼和工具鏈必須確保它char確實是wchar_tWCHAR。

    如果是,那么你的做法應該沒問題;否則就不是。你應該驗證這一點。

uintptr關于在表達式之間傳遞 s 的注意事項

Go 具有垃圾收集功能,因此它的運行時必須知道指向所有當前活動對象的所有指針。只要存在一個變量,其中包含指向在程序運行時分配的內存塊的指針,該塊就不會被垃圾收集。

unsafe.Pointer算作對內存塊的正確引用,uintptr則不然。這意味著當代碼

p?:=?new(someType)
u?:=?uintptr(unsafe.Pointer(&p))
foo(u)return

p正在運行時,一旦分配了地址,GC 就可以自由地回收由 分配的對象p,因為p是對該對象的唯一引用,但u事實并非如此。

現在考慮參考 Go 實現中的 GC 與程序代碼同時運行。這意味著當foo運行時,GC 也可能會執行,并且它可能會將您的實例someTypefoo.

作為此一般規則的一個例外,Go 編譯器保證uintptr(unsafe.Pointer)同一語言表達式中發生的所有類型轉換都不受 GC 的影響。所以以我們之前的例子為例,這樣做就可以了

foo(uintptr(unsafe.Pointer(new(someType)))return

p?:=?new(someType)
v?:=?unsafe.Pointer(&p)
foo(uintptr(v))return

因為類型轉換發生uintptr在單個表達式中——這是一個函數調用。

因此,您不能將指向 Go 對象的指針作為uintptrs傳遞,除非它們包含從“C 端”獲取的指針。


查看完整回答
反對 回復 2023-06-26
  • 1 回答
  • 0 關注
  • 188 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號