syscall.Write not catching SIGPIPE

644 views
Skip to first unread message

Paul Sbarra

unread,
Jan 19, 2012, 2:59:11 PM1/19/12
to golang-nuts
I've come across a situation where a write to network connection is
failing silently due to (I believe) the connection having been closed
on the remote side, resulting in a sigpipe being sent to the process.
While I don't yet understand why the remote end is hanging up I'm not
sure how to best handle this case.

One approach would have the runtime catch the signal and translate
that to an error to be returned to the caller. Although, I'm not sure
what mechanism the runtime could use to determine what the underlying
cause generated the signal. So, that might not be a viable approach.

Is there anything one can do to test that an io.Writer is good before
calling Write? That would detract from the elegance of using the
interface but would at least be able to handle the error gracefully.

Perhaps the best solution is to have the application add a sigpipe
handler and perform a graceful response. Does anyone have any tricks?

The code to reproduce this case is the following git commit (it seems
dbus doesn't handle anonymous authentication well)
https://github.com/tones111/go-dbus/commit/18c94f7ec8931e2ca84f844c79fd8c02a4b9a797

after cloning, run a "make test" where the test application will run
indefinitely. Likely do to the goroutine listening for responses from
the bus.

Ian Lance Taylor

unread,
Jan 19, 2012, 4:44:33 PM1/19/12
to Paul Sbarra, golang-nuts
Paul Sbarra <sbarr...@gmail.com> writes:

> Is there anything one can do to test that an io.Writer is good before
> calling Write? That would detract from the elegance of using the
> interface but would at least be able to handle the error gracefully.

I don't see how this is possible. The connection could fail between the
test and the call to Write.

> Perhaps the best solution is to have the application add a sigpipe
> handler and perform a graceful response. Does anyone have any tricks?

On tip a Go program will install a SIGPIPE handler which ignores the
signal. That will cause a write to a failed socket connection or pipe
to fail with EPIPE. If an os.File gets more than 10 EPIPE errors, it
will flip the SIGPIPE handler back to the default, and raise a SIGPIPE
signal, causing the program to fail.

As far as I know a write to a network socket will simply return an EPIPE
error.

Are you sure you are getting a SIGPIPE signal? What OS? Are you on
weekly or r60?

Ian

Paul Sbarra

unread,
Jan 19, 2012, 5:54:34 PM1/19/12
to golang-nuts
> Are you sure you are getting a SIGPIPE signal?  What OS?  Are you on
> weekly or r60?

Thanks Ian.

This is on linux (kernel 3.1.9) x86_64 running "weekly.2012-01-15
11253+"

I was able to determine it was a sigpipe from running the test in gdb.

.........
Reading symbols from /home/paul/src/go-dbus/6.out...done.
(gdb) run
Starting program: /home/paul/src/go-dbus/6.out
[Thread debugging using libthread_db enabled]
[New Thread 0x7ffff781b700 (LWP 16921)]
[New Thread 0x7ffff701a700 (LWP 16922)]

Program received signal SIGPIPE, Broken pipe.
syscall.Syscall () at /home/paul/src/go/src/pkg/syscall/
asm_linux_amd64.s:24
24 CMPQ AX, $0xfffffffffffff001
(gdb) bt
#0 syscall.Syscall () at /home/paul/src/go/src/pkg/syscall/
asm_linux_amd64.s:24
#1 0x00000000004bd49e in syscall.Write (fd=7, p=..., n=1073865368,
err=...) at /home/paul/src/go/src/pkg/syscall/zsyscall_linux_amd64.go:
903
#2 0x000000000047992a in net.(*netFD).Write (fd=0xf84002b000, p=...,
n=248, err=...) at /home/paul/src/go/src/pkg/net/fd.go:505
#3 0x000000000048bcd1 in net.(*UnixConn).Write (c=0xf84001e128,
b=..., n=0, err=...) at /home/paul/src/go/src/pkg/net/
unixsock_posix.go:135
#4 0x000000000041fb47 in github.com/norisatir/go-dbus.
(*Connection)._SendSync (p=0xf8400011e0, msg=0xf84001cf30,
callback=void, noname=void)
at /home/paul/src/go-dbus/dbus.go:285
#5 0x0000000000420080 in github.com/norisatir/go-dbus.
(*Connection).Call (p=0xf8400011e0, method=0xf84000d7a0, args=...,
noname=void)
at /home/paul/src/go-dbus/dbus.go:370
#6 0x000000000041fbfa in github.com/norisatir/go-dbus.
(*Connection)._SendHello (p=0xf8400011e0, noname=void) at /home/paul/
src/go-dbus/dbus.go:292
#7 0x000000000041f4be in github.com/norisatir/go-dbus.
(*Connection).Authenticate (p=0xf8400011e0, noname=void)
at /home/paul/src/go-dbus/dbus.go:210
#8 0x0000000000420943 in github.com/norisatir/go-dbus.TestDBus
(t=0xf840000cb0) at /home/paul/src/go-dbus/dbus_test.go:48
#9 0x000000000042be5b in testing.tRunner (t=0xf840000cb0,
test=0x605188) at /home/paul/src/go/src/pkg/testing/testing.go:226
#10 0x000000000040df72 in schedunlock () at /home/paul/src/go/src/pkg/
runtime/proc.c:254
#11 0x000000f840000cb0 in ?? ()
#12 0x0000000000605188 in ?? ()
#13 0x0000000000000000 in ?? ()
(gdb)

Ian Lance Taylor

unread,
Jan 19, 2012, 7:42:20 PM1/19/12
to Paul Sbarra, golang-nuts
Paul Sbarra <sbarr...@gmail.com> writes:

> I was able to determine it was a sigpipe from running the test in gdb.
>
> .........
> Reading symbols from /home/paul/src/go-dbus/6.out...done.
> (gdb) run
> Starting program: /home/paul/src/go-dbus/6.out
> [Thread debugging using libthread_db enabled]
> [New Thread 0x7ffff781b700 (LWP 16921)]
> [New Thread 0x7ffff701a700 (LWP 16922)]
>
> Program received signal SIGPIPE, Broken pipe.

Ah, but this by itself doesn't prove anything. gdb stops when the
program receives any signal, in order to let you debug. The question is
what happens when you continue. If all is working well, the program
should simply catch and ignore the signal, which should in turn cause
the system call to return with an EPIPE error.

Ian

Paul Sbarra

unread,
Jan 19, 2012, 6:09:55 PM1/19/12
to golang-nuts
I'm seeing the same behavior on tip

version: weekly.2012-01-15 11354+

.....

Reading symbols from /home/paul/src/go-dbus/6.out...done.
(gdb) run
Starting program: /home/paul/src/go-dbus/6.out
[Thread debugging using libthread_db enabled]
[New Thread 0x7ffff781b700 (LWP 23944)]
[New Thread 0x7ffff701a700 (LWP 23945)]

Program received signal SIGPIPE, Broken pipe.
syscall.Syscall () at /home/paul/src/go/src/pkg/syscall/
asm_linux_amd64.s:24
24 CMPQ AX, $0xfffffffffffff001
(gdb) bt
#0 syscall.Syscall () at /home/paul/src/go/src/pkg/syscall/
asm_linux_amd64.s:24
#1 0x00000000004bd810 in syscall.Write (fd=7, p=..., n=1073865360,
err=...) at /home/paul/src/go/src/pkg/syscall/zsyscall_linux_amd64.go:
903
#2 0x0000000000479baf in net.(*netFD).Write (fd=0xf84001c090, p=...,
n=248, err=...) at /home/paul/src/go/src/pkg/net/fd.go:483
#3 0x000000000048befd in net.(*UnixConn).Write (c=0xf84001e120,
b=..., n=0, err=...) at /home/paul/src/go/src/pkg/net/
unixsock_posix.go:136
#4 0x000000000041fb47 in github.com/norisatir/go-dbus.
(*Connection)._SendSync (p=0xf8400011e0, msg=0xf84001cf30,
callback=void, noname=void)
at /home/paul/src/go-dbus/dbus.go:285
#5 0x0000000000420080 in github.com/norisatir/go-dbus.
(*Connection).Call (p=0xf8400011e0, method=0xf84000d7a0, args=...,
noname=void)
at /home/paul/src/go-dbus/dbus.go:370
#6 0x000000000041fbfa in github.com/norisatir/go-dbus.
(*Connection)._SendHello (p=0xf8400011e0, noname=void) at /home/paul/
src/go-dbus/dbus.go:292
#7 0x000000000041f4be in github.com/norisatir/go-dbus.
(*Connection).Authenticate (p=0xf8400011e0, noname=void)
at /home/paul/src/go-dbus/dbus.go:210
#8 0x0000000000420943 in github.com/norisatir/go-dbus.TestDBus
(t=0xf840000d20) at /home/paul/src/go-dbus/dbus_test.go:48
#9 0x000000000042be21 in testing.tRunner (t=0xf840000d20,
test=0x606188) at /home/paul/src/go/src/pkg/testing/testing.go:254
#10 0x000000000040df72 in schedunlock () at /home/paul/src/go/src/pkg/
runtime/proc.c:254
#11 0x000000f840000d20 in ?? ()
#12 0x0000000000606188 in ?? ()

Ian Lance Taylor

unread,
Jan 20, 2012, 9:40:17 AM1/20/12
to Paul Sbarra, golang-nuts
Paul Sbarra <sbarr...@gmail.com> writes:

> I'm seeing the same behavior on tip
>
> version: weekly.2012-01-15 11354+
>
> .....
>
> Reading symbols from /home/paul/src/go-dbus/6.out...done.
> (gdb) run
> Starting program: /home/paul/src/go-dbus/6.out
> [Thread debugging using libthread_db enabled]
> [New Thread 0x7ffff781b700 (LWP 23944)]
> [New Thread 0x7ffff701a700 (LWP 23945)]
>
> Program received signal SIGPIPE, Broken pipe.


Again, this is expected behaviour when using gdb. It doesn't tell us
anything about how the program behaves when not using gdb.

Ian

Paul Sbarra

unread,
Jan 20, 2012, 11:46:35 PM1/20/12
to golang-nuts
My apologies, my second trace was submitted before your response.
Sorry for the double post. I've traced the problem down to another
section in the lib that is not propagating errors through to the
caller. Fortunately I didn't write that part. Thanks for the
insight. Glad the problem was on my end. ;o)
Reply all
Reply to author
Forward
0 new messages