How to capture stderr/stdout of cgo calls?

1,319 views
Skip to first unread message

Markus Zimmermann

unread,
Jul 25, 2016, 5:56:20 AM7/25/16
to golang-nuts
Given the following code https://play.golang.org/p/1_Q9SFIPjr one can see that stdout of Go and cgo are piped to two different descriptors.

a.) Is it possible to redirect stderr/stdout of cgo calls directly to os.Stderr/os.Stdout? Am I overlooking some argument or options of cgo so that is done automatically during compilation?
b.) Are there any hacks to accomplish the capturing involving only Go code?
c.) Is there a solution at all?

Either my Google-foo is not strong enough or nobody ever posted this on the mailing list or some blog.

Cheers,
Markus

Uli Kunitz

unread,
Jul 25, 2016, 7:00:46 AM7/25/16
to golang-nuts
Your program doesn't work because changing os.Stdout and os.Stdin has no effect on stdio stdin and stdout. Stdio stdout will still reference fd 1 and stderr fd 2.
 
I recommend following three solutions:

  1. The simplest approach could be not to use cgo at all and run the C code in a separate process. Capturing the output of a separate process is simple and can be done using the os/exec package.
  2. Reset stdin and stdout using fdopen in the C code. This could be done permanently.
  3. Swap file descriptors using dup2.
 
 
 

Markus Zimmermann

unread,
Aug 4, 2016, 7:07:40 AM8/4/16
to golang-nuts
I feared that there would be no pure Go solution. Anyway, I used fdopen variant the code is here https://github.com/zimmski/osutil/blob/master/capture.go#L51 if anyone every stumbles over this thread.

Thanks for the help.

Seb Binet

unread,
Aug 4, 2016, 12:58:06 PM8/4/16
to Markus Zimmermann, golang-nuts
On Thu, Aug 4, 2016 at 1:07 PM, Markus Zimmermann <zim...@gmail.com> wrote:
I feared that there would be no pure Go solution. Anyway, I used fdopen variant the code is here https://github.com/zimmski/osutil/blob/master/capture.go#L51 if anyone every stumbles over this thread.

seems to me like you're leaking C.CString("w") at:

it's allocated from cgo so you need to:
cw := C.CString("w")
defer C.free(unsafe.Pointer(cw))
// ...

-s
 

Thanks for the help.


On Monday, July 25, 2016 at 1:00:46 PM UTC+2, Uli Kunitz wrote:
Your program doesn't work because changing os.Stdout and os.Stdin has no effect on stdio stdin and stdout. Stdio stdout will still reference fd 1 and stderr fd 2.
 
I recommend following three solutions:

  1. The simplest approach could be not to use cgo at all and run the C code in a separate process. Capturing the output of a separate process is simple and can be done using the os/exec package.
  2. Reset stdin and stdout using fdopen in the C code. This could be done permanently.
  3. Swap file descriptors using dup2.
 
 
 

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

mattn

unread,
Aug 4, 2016, 10:52:57 PM8/4/16
to golang-nuts
I guess calling freopen is better because cgo possibly having reference of stdin/stdout as FILE*.

Markus Zimmermann

unread,
Aug 5, 2016, 2:51:08 AM8/5/16
to golang-nuts, zim...@gmail.com
You are right Sebastien, I fixed that. Thanks!
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.

Markus Zimmermann

unread,
Aug 5, 2016, 3:00:36 AM8/5/16
to golang-nuts
The documentaton says that freopen closes the original stream. Wouldn't that mean, that it is not possible to restore the origianl stderr/stdout?
Reply all
Reply to author
Forward
0 new messages