gpt4 book ai didi

c++ - 调用Syscall函数时获取异常

转载 作者:IT王子 更新时间:2023-10-29 02:18:48 29 4
gpt4 key购买 nike

我正在使用Go的syscall程序包来调用用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 0x7fffe30bdb33
PC=0x7fffe30bdb33

syscall.Syscall9(0x7fffe32db600, 0x7, 0x97db50, 0xc00007ff10,
0xc00007ff70, 0xc000054180, 0xc0000541a0, 0xc0000541c0, 0xc0000541e0,
0x0, ...)

c:/go/src/runtime/syscall_windows.go:210 +0xf3
main.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

最佳答案

那个设定
所以,基本上,您得到的映射是

  • int* bufferbuffer uintptr
  • int argcunsafe.Pointer(&argsCount),其中&argsCount是指向int的指针
  • char* argv[]unsafe.Pointer(&args),其中args[]string
  • const char* fileNameunsafe.Pointer(syscall.StringToUTF16Ptr(fileName))const char* keyconst char* prefixconst char* version-与上述相同。

  • 问题所在
    现在这是怎么回事。
  • 禁止在函数之间传递包含实时Go对象地址的uintptr值。 (稍后对此有更多介绍。)
  • 您将argsCount函数参数的地址传递给argc。如果将其解释为计数,那么在典型的商品平台/操作系统(例如amd64/Windows)上的地址就是一个巨大的值(value)。
    我敢打赌,该函数在尝试从argv中读取许多元素时会崩溃—导致其读取您的进程未映射的内存。
  • 这里有两个问题:
  • 将 slice 值的地址作为参数传递而期望该 slice 的第一个元素的地址是错误的。
    这是因为slice值(当前,在您正在使用的“引用” Go实现中)是具有3个字段的struct:基础数据数组的地址,该数组中允许使用的元素数以及在 slice 值上调用时,append函数可在不重新分配的情况下使用该数组中此类元素的总数。
    当您具有args []string并执行&args时,您将获得该结构的地址,而不是该 slice 的第一个元素的地址。
    要执行后者,请使用&args[0]
  • 在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()

  • 您准备将字符串数据传递给具有const char*类型的其余参数的准备工作似乎是正确的,但前提是被叫方确实表示其char是16位整数。
    换句话说,用于编译该库的源代码和工具链必须确保char实际上是 wchar_t or WCHAR
    如果是,那么您应该做的事;否则不是。您应该对此进行验证。

  • 关于在表达式之间传递 uintptr的说明
    Go具有垃圾回收功能,因此它的运行时必须知道指向所有当前 Activity 对象的所有指针。只要存在一个包含指向程序运行时分配的内存块的指针的变量,该块就不会被垃圾回收。 unsafe.Pointer值算作对存储块的正确引用,但 uintptr不算。 这意味着当代码
    p := new(someType)
    u := uintptr(unsafe.Pointer(&p))
    foo(u)
    return
    在运行时,一旦分配了 p地址,GC便可以随意回收 p分配的对象-这是因为 p是对该对象的唯一引用,而 u不是。
    现在考虑引用Go实现中的GC与程序代码同时运行。
    这意味着当 foo运行时,可能也会执行GC,并且可能会从 someType的脚下扫掠 foo实例。
    作为该通用规则的异常(exception),Go编译器保证以相同语言表达形式进行的所有 uintptr(unsafe.Pointer)类型转换均不受GC的影响。因此,以我们之前的示例为例,就可以了
    foo(uintptr(unsafe.Pointer(new(someType)))
    return

    p := new(someType)
    v := unsafe.Pointer(&p)
    foo(uintptr(v))
    return
    因为将类型转换为 uintptr的过程是在单个表达式中进行的-这是一个函数调用。
    因此,除非包含从“C端”获得的指针,否则不得将指针作为Got对象传递给 uintptr

    关于c++ - 调用Syscall函数时获取异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56755969/

    29 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com