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

runtime: Go runtime in DLL marks stdin/out/err not inherited on Windows #24328

Open
tomcnolan opened this Issue Mar 9, 2018 · 3 comments

Comments

Projects
None yet
4 participants
@tomcnolan

tomcnolan commented Mar 9, 2018

Please answer these questions before submitting your issue. Thanks!

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

go version go1.10 windows/amd64

Does this issue reproduce with the latest release?

Yes

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

GOARCH=amd64
GOHOSTARCH=amd64
GOHOSTOS=windows
GOOS=windows

What did you do?

Source file godll.go

package main
import "C"
import "fmt"
func main () {}
//export goFunc
func goFunc () { fmt.Printf ("goFunc called\n") }

Command to build godll.dll from source file godll.go

go build -buildmode=c-shared -o godll.dll

Python source file loadgo.py

import ctypes
def loadgo():
    help(print)
    godll = ctypes.cdll.LoadLibrary("godll.dll")
    godll.goFunc()
    help(print)

Command Prompt Window commands and output

Note that these commands are executed interactively with an interactive Python interpreter.

py -3
Python 3.4.3 (v3.4.3:9b73f1c3e601, Feb 24 2015, 22:44:40) [MSC v.1600 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import loadgo
>>> loadgo.loadgo()
Help on built-in function print in module builtins:

print(...)
    print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)

    Prints the values to a stream, or to sys.stdout by default.
    Optional keyword arguments:
    file:  a file-like object (stream); defaults to the current sys.stdout.
    sep:   string inserted between values, default a space.
    end:   string appended after the last value, default a newline.
    flush: whether to forcibly flush the stream.

goFunc called

>>>

What did you expect to see?

The Python function executes the help(print) command before and after loading the godll.dll and calling its exported function goFunc.

I expected to see the help(print) command output both before and after the printed line "goFunc called".

What did you see instead?

I only see the help(print) command output before the printed line "goFunc called".

The Python help command output is broken after the Go runtime is loaded into the Python interpreter process.

The Python help command works by storing the help command output in a temporary text file and then spawning the "more" command to read from the temporary text file.

The Python interpreter expects that the stdout file handle will be inherited by the spawned "more" command.

When a DLL built with Go is dynamically linked-to in a process, then during the Go runtime initialization, the Go runtime sets "CloseOnExec" behavior for the stdin, stdout, and stderr handles.

That behavior is due to the following code in C:\go\src\syscall\syscall_windows.go

var (
	Stdin  = getStdHandle(STD_INPUT_HANDLE)
	Stdout = getStdHandle(STD_OUTPUT_HANDLE)
	Stderr = getStdHandle(STD_ERROR_HANDLE)
)

func getStdHandle(h int) (fd Handle) {
	r, _ := GetStdHandle(h)
	CloseOnExec(r)
	return r
}

If I comment out this line of code in the Go runtime:

	//CloseOnExec(r)

Then the Go runtime no longer breaks the Python help command, and the output from the second help command is visible after the line "goFunc called".

py -3
Python 3.4.3 (v3.4.3:9b73f1c3e601, Feb 24 2015, 22:44:40) [MSC v.1600 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import loadgo
>>> loadgo.loadgo()
Help on built-in function print in module builtins:

print(...)
    print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)

    Prints the values to a stream, or to sys.stdout by default.
    Optional keyword arguments:
    file:  a file-like object (stream); defaults to the current sys.stdout.
    sep:   string inserted between values, default a space.
    end:   string appended after the last value, default a newline.
    flush: whether to forcibly flush the stream.

goFunc called
Help on built-in function print in module builtins:

print(...)
    print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)

    Prints the values to a stream, or to sys.stdout by default.
    Optional keyword arguments:
    file:  a file-like object (stream); defaults to the current sys.stdout.
    sep:   string inserted between values, default a space.
    end:   string appended after the last value, default a newline.
    flush: whether to forcibly flush the stream.

>>>

In my opinion, when the Go runtime is within a DLL, the Go runtime should not call CloseOnExec for the std handles. A DLL is a guest within the process and a DLL should not assume that it owns or controls the std handles.

This behavior of the Go runtime within a Windows DLL is an impediment to creating DLLs in Go that can be used by Python.

My current workaround is to comment out the problematic line of code in the Go runtime, but there are obvious drawbacks to that workaround.

  • The code must be commented out again each time I download a new version of Go.
  • The change affects both EXEs and DLLs created with Go. Preferably, the Go runtime would behave appropriately and distinguish between EXEs and DLLs, and provide the appropriate behavior for the two kind of build output: CloseOnExec for EXEs, but no CloseOnExec for DLLs.

@ALTree ALTree changed the title from Go runtime in DLL breaks interactive Python help command to runtime: Fo runtime in DLL breaks interactive Python help command Mar 9, 2018

@ALTree ALTree changed the title from runtime: Fo runtime in DLL breaks interactive Python help command to runtime: Go runtime in DLL breaks interactive Python help command Mar 9, 2018

@ALTree ALTree added this to the Go1.11 milestone Mar 9, 2018

@alexbrainman

This comment has been minimized.

Member

alexbrainman commented Mar 18, 2018

In my opinion, when the Go runtime is within a DLL, the Go runtime should not call CloseOnExec for the std handles.

I agree. I think we should fix this. It would be nice to have a test for this too.

@tomcnolan would you like to send a fix? This https://golang.org/doc/contribute.html is how to contribute.

Alex

@tomcnolan

This comment has been minimized.

tomcnolan commented Mar 19, 2018

Let me research what a proper fix would look like. Then I will need to ask my company's legal dept about contributing. So ... a solid maybe.

@alexbrainman

This comment has been minimized.

Member

alexbrainman commented Mar 20, 2018

Let me research what a proper fix would look like. Then I will need to ask my company's legal dept about contributing. So ... a solid maybe.

OK

Alex

@ianlancetaylor ianlancetaylor changed the title from runtime: Go runtime in DLL breaks interactive Python help command to runtime: Go runtime in DLL marks stdin/out/err not inherited on Windows Jul 7, 2018

@ianlancetaylor ianlancetaylor modified the milestones: Go1.11, Go1.12 Jul 10, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment