Should it panic when set a channel to nil concurrently

133 views
Skip to first unread message

Yuan Ting

unread,
Mar 1, 2020, 11:49:34 PM3/1/20
to golang-nuts
I write a simple program likes below and it triggers a data race alarm with -race flag. But no matter how I run, this program will not panic. I know it is legal to receive messages from nil channels, but I don't quite understand why this program does not panic in the presence of data races.

ch := make(chan struct{})
go func() {
ch = nil
}()
go func() {
<-ch
}()



burak serdar

unread,
Mar 2, 2020, 12:37:01 AM3/2/20
to Yuan Ting, golang-nuts
On Sun, Mar 1, 2020 at 9:49 PM Yuan Ting <yuan...@ict.ac.cn> wrote:
>
> I write a simple program likes below and it triggers a data race alarm with -race flag. But no matter how I run, this program will not panic. I know it is legal to receive messages from nil channels, but I don't quite understand why this program does not panic in the presence of data races.

Why should it panic? The first goroutine simply sets the channel to
nil. The second goroutine will either block reading from a non-nil
channel, or block reading from a nil channel. There is no code in this
program that would panic.

>
> ch := make(chan struct{})
> go func() {
> ch = nil
> }()
> go func() {
> <-ch
> }()
>
>
>
> --
> 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...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/02e2fa3e-1952-4dda-8bfa-18f619e21ec9%40googlegroups.com.

Jan Mercl

unread,
Mar 2, 2020, 12:49:46 AM3/2/20
to burak serdar, Yuan Ting, golang-nuts
On Mon, Mar 2, 2020 at 6:36 AM burak serdar <bse...@computer.org> wrote:

> Why should it panic? The first goroutine simply sets the channel to
> nil. The second goroutine will either block reading from a non-nil
> channel, or block reading from a nil channel. There is no code in this
> program that would panic.

It can panic.

1) The channel receive sees that the channel is non nil
2) The other goroutine concurrently sets the channel to nil
3) GC kicks in and frees the channel memory
4) Something else allocates and overwrites the memory that was
previously used by the channel. That could be the GC itself.
5) The channel receive goroutine now continues to receive using memory
data that are no more representing a channel.

burak serdar

unread,
Mar 2, 2020, 12:56:45 AM3/2/20
to Jan Mercl, Yuan Ting, golang-nuts
On Sun, Mar 1, 2020 at 10:49 PM Jan Mercl <0xj...@gmail.com> wrote:
>
> On Mon, Mar 2, 2020 at 6:36 AM burak serdar <bse...@computer.org> wrote:
>
> > Why should it panic? The first goroutine simply sets the channel to
> > nil. The second goroutine will either block reading from a non-nil
> > channel, or block reading from a nil channel. There is no code in this
> > program that would panic.
>
> It can panic.
>
> 1) The channel receive sees that the channel is non nil
> 2) The other goroutine concurrently sets the channel to nil
> 3) GC kicks in and frees the channel memory

At this point, channel receive is still holding a reference to the
channel (right?), so GC cannot free it.

Jan Mercl

unread,
Mar 2, 2020, 1:11:47 AM3/2/20
to burak serdar, Yuan Ting, golang-nuts
On Mon, Mar 2, 2020 at 6:56 AM burak serdar <bse...@computer.org> wrote:

> At this point, channel receive is still holding a reference to the
> channel (right?), so GC cannot free it.

Depends very much on what code the compiler for channel receive
generates and on the code in the runtime that implements the channel
receive.

There are no data races that can be guaranteed 100% safe from the
language specification/memory model POV.

Yuan Ting

unread,
Mar 2, 2020, 1:35:01 AM3/2/20
to golang-nuts
I'm not sure if the channel receive is atomic. I thought it would get a null pointer dereference error in chanrecv at runtime.


On Monday, March 2, 2020 at 1:37:01 PM UTC+8, burak serdar wrote:
On Sun, Mar 1, 2020 at 9:49 PM Yuan Ting <yuan...@ict.ac.cn> wrote:
>
> I write a simple program likes below and it triggers a data race alarm with -race flag. But no matter how I run, this program will not panic. I know it is legal to receive messages from nil channels, but I don't quite understand why this program does not panic in the presence of data races.

Why should it panic? The first goroutine simply sets the channel to
nil. The second goroutine will either block reading from a non-nil
channel, or block reading from a nil channel. There is no code in this
program that would panic.

>
> ch := make(chan struct{})
> go func() {
> ch = nil
> }()
> go func() {
> <-ch
> }()
>
>
>
> --
> 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 golan...@googlegroups.com.

Yuan Ting

unread,
Mar 2, 2020, 1:41:24 AM3/2/20
to golang-nuts
How about the main go compiler? Will the code generated by the main go compiler panic as you analyze?

Brian Candler

unread,
Mar 2, 2020, 6:20:32 AM3/2/20
to golang-nuts
On Monday, 2 March 2020 04:49:34 UTC, Yuan Ting wrote:
I write a simple program likes below and it triggers a data race alarm with -race flag. But no matter how I run, this program will not panic. I know it is legal to receive messages from nil channels, but I don't quite understand why this program does not panic in the presence of data races.

Because not all data races cause panics.

A data race is where the behaviour of the program is non-deterministic - it could do either A or B depending on the precise timing of other things going on - but it doesn't necessarily mean that a panic will happen.

Marvin Renich

unread,
Mar 2, 2020, 8:37:23 AM3/2/20
to golang-nuts
* Yuan Ting <yuan...@ict.ac.cn> [200301 23:50]:
I think the other responses missed the obvious here (or at least chose
more elaborate, though correct, explanations). This is a variable
assignment in one goroutine concurrent with a variable reference in
another. It is exactly the same (from the point of view of whether it
is a race or not) as this:

var a = 17

go func() {
a = 987654
}()

go func() {
fmt.Println(a)
}

In the second goroutine, the variable a might have the value 17, it
might have the value 987654, and it might have garbage that is neither
of these. This is a race condition, and it is also true of the channel
code above.

One of the other responses very correctly said that a race does not
imply that the code could panic. The integer code above will never
panic, even on architectures where a write of an integer to memory
concurrent with a read from that memory can possibly allow the read to
return partially written data. However, the above code is clearly a
race condition.

...Marvin

Jake Montgomery

unread,
Mar 2, 2020, 12:11:07 PM3/2/20
to golang-nuts
Good explanation, Marvin. This is precisely why we have the race detector. If all races produced a panic, then it would not be needed. Some races behave "correctly" for a long time, and only on rare occasion result in silent data corruption that can be almost impossible to debug. Other races might result in frequent panics. But no races are "safe", and all code should be race free.
Reply all
Reply to author
Forward
0 new messages