Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

syscall: NewCallback panics when given a callback function with no return type #30070

Closed
MShoaei opened this issue Feb 3, 2019 · 11 comments
Closed
Labels
FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. OS-Windows

Comments

@MShoaei
Copy link

MShoaei commented Feb 3, 2019

What version of Go are you using (go version)?

$ go version
go version go1.11.5 windows/amd64

Does this issue reproduce with the latest release?

yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
set GOARCH=amd64
set GOEXE=.exe
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOOS=windows

What did you do?

just copy this code, try to run it and it will panic

What did you expect to see?

code compile and execute sucessfully

What did you see instead?

PANIC!

@tklauser
Copy link
Member

tklauser commented Feb 3, 2019

/cc @alexbrainman

@tklauser tklauser added OS-Windows NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. labels Feb 3, 2019
@odeke-em
Copy link
Member

odeke-em commented Feb 3, 2019

Thank you for the report @MShoaei and welcome to the Go project, and thanks @tklauser for the triaging.

@MShoaei what's the oldest version of Go that you can reproduce this on? Go1.9, Go1.10? What are the results on Go1.12beta*? Thanks.

@MShoaei
Copy link
Author

MShoaei commented Feb 3, 2019

@odeke-em I was able to reproduce the issue with Go1.12beta2.
I can't install previous versions of Go on my machine so I can't say anything about previous versions, but I think there is a 90% chance that this issue DO exist in previous versions.
Also I managed to find a workaround: using uintptr as the return type of the callback function solves the issue.
I wonder what does a function return when there are no return types defined for the function?

@odeke-em
Copy link
Member

odeke-em commented Feb 3, 2019

@MShoaei thanks for the confirmation. I had asked a generic question to help determine the triaging stage.

but I think there is a 90% chance that this issue DO exist in previous versions.
Also I managed to find a workaround: using uintptr as the return type of the callback function solves the issue.
I wonder what does a function return when there are no return types defined for the function?

Anyways, I don't think that this is a bug at all, because syscall.NewCallback documents in

// The argument is expected to be a function with one uintptr-sized result. The function must not have arguments with size larger than the size of uintptr.
func NewCallback(fn interface{}) uintptr {

which says The argument is expected to be a function with one uintptr-sized result. so as you've applied, the function MUST have a one uintptr-result.

I wonder what does a function return when there are no return types defined for the function?

It'll panic as you've seen :)

Let's close this issue as it is working as intended, but thank you for keeping vigilant and being a part of the Go community @MShoaei!

@MShoaei
Copy link
Author

MShoaei commented Feb 4, 2019

Anyways, I don't think that this is a bug at all, because syscall.NewCallback documents in

go/src/syscall/syscall_windows.go

Lines 126 to 127 in 8f85424
// The argument is expected to be a function with one uintptr-sized result. The function must not have arguments with size larger than the size of uintptr.
func NewCallback(fn interface{}) uintptr {

which says The argument is expected to be a function with one uintptr-sized result. so as you've applied, the function MUST have a one uintptr-result.

@odeke-em Thanks for your reply
But Windows API documentation in my example requires the callback function to return void, so returning uintptr is a little odd, unless something like below is true in Go:

var a uintptr = 0
var b = nil
a == b

@alexbrainman
Copy link
Member

because syscall.NewCallback documents in
go/src/syscall/syscall_windows.go

Lines 126 to 127 in 8f85424

// The argument is expected to be a function with one uintptr-sized result. The function must not have arguments with size larger than the size of uintptr.
func NewCallback(fn interface{}) uintptr {
which says The argument is expected to be a function with one uintptr-sized result. so as you've applied, the function MUST have a one uintptr-result.

Yes, that is how syscallback.NewCallback was designed. All callbacks we required in our code had return value.

But Windows API documentation in my example requires the callback function to return void, so returning uintptr is a little odd

Yes, I can see WINEVENTPROC callback function returns void. Like I said before, we have never encountered callback function that returned no value. Until now.

I am not sure we need to change anything, because return value is returned in AX register for both 386 and amd64, so Windows will just ignore whatever value you will return.

Alternatively we could remove syscall.NewCallback panic, when callback return no value.

I am not fussed either way.

Alex

@MShoaei
Copy link
Author

MShoaei commented Feb 4, 2019

@alexbrainman But I guess relying on how Windows will treat our return value and hoping it won't break isn't so convenient, don't you think?
I think modifying syscall.NewCallback is a better way to take than just ignoring these slightly rare situations.

@alexbrainman
Copy link
Member

But I guess relying on how Windows will treat our return value and hoping it won't break isn't so convenient, don't you think?

You won't rely on Windows for anything. Windows will ignore whatever is in AX register when WINEVENTPROC returns. So it does not matter, if your syscall.NewCallback parameter function return value or not.

I think modifying syscall.NewCallback is a better way to take than just ignoring these slightly rare situations.

I disagree. Nearly all callback functions return values. I want my program to panic, if I forget to return value from my callback function.

Alex

@MShoaei
Copy link
Author

MShoaei commented Feb 4, 2019

@alexbrainman Maybe a little documentation for such situations? 😞
And with that I guess we can close this issue.
Thank you for your replies.

@alexbrainman
Copy link
Member

And with that I guess we can close this issue

I will let others decide what to do here.

Thank you for your replies.

No worries.

Alex

@MShoaei MShoaei closed this as completed May 31, 2019
@tomcanham
Copy link

tomcanham commented May 6, 2020

Technically speaking, you can't "return void" in C/C++, since all the ABI's that I'm aware of return results in EAX. So even if your function is defined with a void return type, there is still a "return value" in EAX, even if it's utterly undefined as to what it is. It's basically how the __stdcall calling convention works, which is utterly irrelevant now that all modern code no longer uses __cdecl.

Aren't high-level/low-level language interfaces fun?

@golang golang locked and limited conversation to collaborators May 6, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. OS-Windows
Projects
None yet
Development

No branches or pull requests

6 participants