调用Go中的NotifyIpInterfaceChange导致了访问冲突异常。

huangapple go评论192阅读模式
英文:

Calling NotifyIpInterfaceChange from Go caused Access Violation exceptions

问题

这是我第一次从Go中调用本地库进行调用。

我正在尝试使用Windows库设置事件钩子,以便监听网络接口的变化,到目前为止,我已经成功地使用NotifyAddrChange设置了一个监听器。

现在我正在尝试使用以下代码来使用NotifyIpInterfaceChange

  1. package main
  2. import (
  3. "golang.org/x/sys/windows"
  4. "log"
  5. "syscall"
  6. "unsafe"
  7. )
  8. var (
  9. modiphlpapi = windows.NewLazySystemDLL("iphlpapi.dll")
  10. procNotifyIpInterfaceChange = modiphlpapi.NewProc("NotifyIpInterfaceChange")
  11. )
  12. type context struct{}
  13. func main() {
  14. log.Printf("Loaded [iphlpapi.dll] at {%#v}", modiphlpapi.Handle())
  15. log.Printf("Found [NotifyIpInterfaceChange] at {%#v}", procNotifyIpInterfaceChange.Addr())
  16. context := &context{}
  17. interfaceChange := windows.Handle(0)
  18. ret, _, errNum := procNotifyIpInterfaceChange.Call(syscall.AF_UNSPEC, syscall.NewCallback(callback), uintptr(unsafe.Pointer(context)), 0, uintptr(interfaceChange))
  19. log.Printf("%#v %#v", ret, errNum)
  20. }
  21. func callback(callerContext, row, notificationType uintptr) uintptr {
  22. log.Printf("callback invoked by Windows API (%#v %#v %#v)", callerContext, row, notificationType)
  23. return 0
  24. }

代码可以正常编译并启动,没有任何问题,但是一旦调用函数,我就会得到以下异常:

  1. D:\>event-listen_type2.exe
  2. 2017/06/22 22:12:39 Loaded [iphlpapi.dll] at {0x7ffac96f0000}
  3. 2017/06/22 22:12:39 Found [NotifyIpInterfaceChange] at {0x7ffac96f7e20}
  4. Exception 0xc0000005 0x1 0x0 0x7ffac96f7edb
  5. PC=0x7ffac96f7edb
  6. syscall.Syscall6(0x7ffac96f7e20, 0x5, 0x0, 0x454170, 0x54d360, 0x0, 0x0, 0x0, 0xc042015350, 0xc042015300, ...)
  7. /usr/local/Cellar/go/1.8.3/libexec/src/runtime/syscall_windows.go:174 +0x6b
  8. github.com/LiamHaworth/windows-network-events/vendor/golang.org/x/sys/windows.(*Proc).Call(0xc04203a620, 0xc042050300, 0x5, 0x5, 0x30, 0x4b12e0, 0x1, 0xc042050300)
  9. /Users/liam/git/go_path/src/github.com/LiamHaworth/windows-network-events/vendor/golang.org/x/sys/windows/dll_windows.go:139 +0x5c1
  10. github.com/LiamHaworth/windows-network-events/vendor/golang.org/x/sys/windows.(*LazyProc).Call(0xc042050270, 0xc042050300, 0x5, 0x5, 0x1, 0xc04201a000, 0xc04202df78, 0x4043a3)
  11. /Users/liam/git/go_path/src/github.com/LiamHaworth/windows-network-events/vendor/golang.org/x/sys/windows/dll_windows.go:309 +0x66
  12. main.main()
  13. /Users/liam/git/go_path/src/github.com/LiamHaworth/windows-network-events/main_windows.go:25 +0x229
  14. rax 0x0
  15. rbx 0xc3f10
  16. rcx 0x1fb5cd87abfd0000
  17. rdi 0x0
  18. rsi 0x454170
  19. rbp 0xc04202dc00
  20. rsp 0x8fdf0
  21. r8 0x8fb78
  22. r9 0x7ffac96fb4c0
  23. r10 0x0
  24. r11 0x8fcf0
  25. r12 0x0
  26. r13 0xffffffee
  27. r14 0x0
  28. r15 0xaa
  29. rip 0x7ffac96f7edb
  30. rflags 0x10246
  31. cs 0x33
  32. fs 0x53
  33. gs 0x2b

通过一些搜索,我知道异常类型0xc0000005是CPU在程序尝试访问未分配给它的内存时抛出的访问冲突,但是通过查看我的代码,我无法确定发生了什么。所有传递的指针都是应用程序中的项目。

在这里任何帮助都将是非常宝贵的。

英文:

This is the first time I have had to make calls to native libraries from Go.

I am trying to setup event hooks with the windows libraries to listen for network interface changes, so far I have been successful with setting up a listener with NotifyAddrChange.

Now I am trying with NotifyIpInterfaceChange with the following code

  1. package main
  2. import (
  3. "golang.org/x/sys/windows"
  4. "log"
  5. "syscall"
  6. "unsafe"
  7. )
  8. var (
  9. modiphlpapi = windows.NewLazySystemDLL("iphlpapi.dll")
  10. procNotifyIpInterfaceChange = modiphlpapi.NewProc("NotifyIpInterfaceChange")
  11. )
  12. type context struct{}
  13. func main() {
  14. log.Printf("Loaded [iphlpapi.dll] at {%#v}", modiphlpapi.Handle())
  15. log.Printf("Found [NotifyIpInterfaceChange] at {%#v}", procNotifyIpInterfaceChange.Addr())
  16. context := &context{}
  17. interfaceChange := windows.Handle(0)
  18. ret, _, errNum := procNotifyIpInterfaceChange.Call(syscall.AF_UNSPEC, syscall.NewCallback(callback), uintptr(unsafe.Pointer(context)), 0, uintptr(interfaceChange))
  19. log.Printf("%#v %#v", ret, errNum)
  20. }
  21. func callback(callerContext, row, notificationType uintptr) uintptr {
  22. log.Printf("callback invoked by Windows API (%#v %#v %#v)", callerContext, row, notificationType)
  23. return 0
  24. }

The code compiles fine and starts up without any issue, the problem happens once the function is invoke, then I get the following exception

  1. D:\>event-listen_type2.exe
  2. 2017/06/22 22:12:39 Loaded [iphlpapi.dll] at {0x7ffac96f0000}
  3. 2017/06/22 22:12:39 Found [NotifyIpInterfaceChange] at {0x7ffac96f7e20}
  4. Exception 0xc0000005 0x1 0x0 0x7ffac96f7edb
  5. PC=0x7ffac96f7edb
  6. syscall.Syscall6(0x7ffac96f7e20, 0x5, 0x0, 0x454170, 0x54d360, 0x0, 0x0, 0x0, 0xc042015350, 0xc042015300, ...)
  7. /usr/local/Cellar/go/1.8.3/libexec/src/runtime/syscall_windows.go:174 +0x6b
  8. github.com/LiamHaworth/windows-network-events/vendor/golang.org/x/sys/windows.(*Proc).Call(0xc04203a620, 0xc042050300, 0x5, 0x5, 0x30, 0x4b12e0, 0x1, 0xc042050300)
  9. /Users/liam/git/go_path/src/github.com/LiamHaworth/windows-network-events/vendor/golang.org/x/sys/windows/dll_windows.go:139 +0x5c1
  10. github.com/LiamHaworth/windows-network-events/vendor/golang.org/x/sys/windows.(*LazyProc).Call(0xc042050270, 0xc042050300, 0x5, 0x5, 0x1, 0xc04201a000, 0xc04202df78, 0x4043a3)
  11. /Users/liam/git/go_path/src/github.com/LiamHaworth/windows-network-events/vendor/golang.org/x/sys/windows/dll_windows.go:309 +0x66
  12. main.main()
  13. /Users/liam/git/go_path/src/github.com/LiamHaworth/windows-network-events/main_windows.go:25 +0x229
  14. rax 0x0
  15. rbx 0xc3f10
  16. rcx 0x1fb5cd87abfd0000
  17. rdi 0x0
  18. rsi 0x454170
  19. rbp 0xc04202dc00
  20. rsp 0x8fdf0
  21. r8 0x8fb78
  22. r9 0x7ffac96fb4c0
  23. r10 0x0
  24. r11 0x8fcf0
  25. r12 0x0
  26. r13 0xffffffee
  27. r14 0x0
  28. r15 0xaa
  29. rip 0x7ffac96f7edb
  30. rflags 0x10246
  31. cs 0x33
  32. fs 0x53
  33. gs 0x2b

From some googling I know that exception type 0xc0000005 is a access violation thrown by the CPU when a program tries to access memory not allocated to it but looking through my code I can't tell where that is happening. All pointers passed are for items in the application.

Any help here would be magnificent.

答案1

得分: 1

根据文档,NotifyIpInterfaceChange 的最新参数是 in/out 类型,并且需要是指向 HANDLE 的指针。将系统调用更改为:

  1. ret, _, errNum := procNotifyIpInterfaceChange.Call(syscall.AF_UNSPEC,
  2. syscall.NewCallback(callback),
  3. uintptr(unsafe.Pointer(context)),
  4. 0,
  5. uintptr(unsafe.Pointer(&interfaceChange))) //this must be pointer

编辑:
如评论中提到的和 这个 go-nuts 讨论 中提到的,对于多线程回调,即使我们不使用 cgo,也需要添加 import "C"

英文:

According to documentation, the latest parameter of NotifyIpInterfaceChange is both in/out and need to be a pointer to HANDLE. Change the system call to:

  1. ret, _, errNum := procNotifyIpInterfaceChange.Call(syscall.AF_UNSPEC,
  2. syscall.NewCallback(callback),
  3. uintptr(unsafe.Pointer(context)),
  4. 0,
  5. uintptr(unsafe.Pointer(&interfaceChange))) //this must be pointer

EDIT:
As mentioned in the comment and this go-nuts discussion, for multi-threaded callback, import "C" need to be added, even if we don't use cgo.

huangapple
  • 本文由 发表于 2017年6月22日 20:41:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/44699710.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定