Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
cmd/cgo: don't use syscall.Errno type as errno return on Windows #23468
Apologies in advance If I'm explaining anything poorly.
What did you do?
I made an Go binding library for a static C lib, then wrote a go application to use that. During the course of developing that application, I managed to trigger the following error:
I have a stripped down testable chunk of code (complete with a more in depth readme) here: https://github.com/technicalviking/cgotest
I'd like to stress: I'm not looking to debug the code itself. I know the outputs are not what I expected (casting the C **double variable back to float64 in 'extractOutputs' shows a significant number of NaN entries, but meh), but rather why the functionality puts the code in a state where a windows error populates the error return value of the go reference to the C function in this case.
EDIT TO INVESTIGATION
On further digging I found that calling
What did you expect to see?
What did you see instead?
calling the c function using the mechanism
pushed a commit
Jan 18, 2018
changed the title from
CGO windows unable to return control of application to Go from C land (unless I ignore the error)?
runtime: CGO windows unable to return control of application to Go from C land (unless I ignore the error)?
Jan 18, 2018
The error message is from windows itself, and happens as the c function in the cgo preamble is returning to go, assuming that cgo function, or any other c function called therein, attempted to call sqrt on a negative number. the actual return value from the cgo function is not adversely affected, but the presence of this error message in the error return value of the go call to the cgo method is perplexing, and i dont understand how its getting there. This also means that, for now, im forced to merely log and ignore the error value when its not nil.…
On Jan 17, 2018 6:06 PM, "Ian Lance Taylor" ***@***.***> wrote: I don't know what that error means. It's not coming from Go. — You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub <#23468 (comment)>, or mute the thread <https://github.com/notifications/unsubscribe-auth/ABeZwhuRZg-ULhgLcuCDgTzehTDjE5Vfks5tLqcjgaJpZM4RiNcL> .
I've managed to get a MUCH simpler version of the code that demonstrates the problem.
Isn't this just the documented cgo behaviour of returning errno when calling a C function in multiple assignment context? If your C function does not set errno, don't expect to find anything meaningful there. It's likely just leftover garbage from whatever its last user happened to put there. Try setting errno to 0 before returning from your C function.
edit: yes it is. The Windows error ERROR_LOCK_VIOLATION is the integer 33, which I guess your libc is using for EDOM, which is what sqrt(3) returns on a domain error (i.e. calling it with a negative argument).
That... tells me everything I need to know (as disappointing as it is...). The ansi c documentation I found does indeed indicate that the EDOM macro is also the integer 33.
However the error interface value being returned outputs as the string mentioned above (when using %v), not the actual integer errno itself. (Further digging reveals that using the %#v verb outputs 0x21, and using the %d verb outputs 33). Given the mismatch between the ansi c errno description, and the OS description for that error code, would it be reasonable to ask that using the %v verb to output the errno value give the ansi c macro name (or some other related value, such as the output of the %#v verb), rather than the host OS interpretation of that code?
The issue is that the Go side doesn't know the error code convention of the called C function. If you call a Windows API function through cgo, that same integer 33 actually means ERROR_LOCK_VIOLATION. You probably don't want the error returned from C.CreateFile to print as "numerical argument out of domain".
You can probably make a list of C standard library functions and special-case them (making the error message from sqrt look right), but there is lots of code outside of libc that uses C-style error conventions. It would just add even more confusion.
It's easier on Unix as those just incorporate the ANSI C errno definitions into the system interface, so this kind of ambiguity doesn't occur there.
That seems like an even better reason to have the %v verb translate the errno to either the integer value (in this case 33) as output by the %d verb, or the hex value (in this case 0x21) as would be output by the %#v verb, instead of the host OS interpretation of that code. If the Go side doesn't know the error code convention of the called C function, then the 'default format' (as described in the documentation of the fmt package for the %v verb) of the error code should be unambiguous as well. I would submit that translating the errno to a useable string should be an exercise for the programmer with a priori knowledge of the C function being called, not an assumption made by Go.
@zhangyoufu IMHO the issue is more concerning the difference in functionality between
Converting the errno to a syscall.Errno makes sense, as far as it goes, but the obfuscation of what happens between operating systems when trying to output the syscall.Errno using the %v verb (which I think calls the .Error() method to get the string value if it's available) feels like there's an assumption that C code used by a developer on windows will always be code accessing the Windows API. Silly me, I stumbled across a bug in the C code I was writing bindings for which had no such goal, and ran face first into a (potentially uncommon) case where this assumption wasn't valid. Part of this is admittedly my lack of experience with the language (I'd been using it for only a paltry few months at the time).
Any of these potential solutions (or anythinig like them) would preclude the need for special interpretation of the %v verb when outputting a syscall.Errno with the fmt package.
If I'm following this correctly, the problem is that C functions on Windows set
Once we have that type, @zhangyoufu already pointed out the line in cgo that needs to change on Windows.