go fails to detect a point-time race condition

148 views
Skip to first unread message

Zhaoxun Yan

unread,
Apr 30, 2022, 1:49:11 AM4/30/22
to golang-nuts
point race means I/O on a global might clash at certain point of time.

consider this example:

package main

import "time"
import "fmt"

var index int64

func increase(){
  index++
}

func read(){
  fmt.Println(index)
}

func main(){
   go func(N){
     for i:=0; i < N; i++{
        increase()
        time.Sleep(500 * time.Millisecond)
     }
 }(5)
   time.Sleep(2 * time.Second)
   read()
}

Obviously, the increase function is writing the global variable 'index' while the read is reading it. It is highly unlikely that they could function at the same time, but not impossible.  Further, if the increase function takes longer time to manipulate the global, such as an array which might enlarge itself, and reading during the changing of the global is dangerous.

The code in my project has a little variation -  the writing of the variable is controlled by crontask of "github.com/robfig/cron". However, the essence is the same. Point-time race condition is undetectable by `go build race`. Thanks to Rust on emphasizing the single entrance to any variable,  I realized this possibility and have to add sync.Mutex to both functions.

What is your opinion?
 
Best Regards,
  Zhaoxun

Axel Wagner

unread,
Apr 30, 2022, 2:05:45 AM4/30/22
to Zhaoxun Yan, golang-nuts
On Sat, Apr 30, 2022 at 7:49 AM Zhaoxun Yan <yan.z...@gmail.com> wrote:
Point-time race condition is undetectable by `go build race`.

When I run your code using `go run -race`, it reports a data race:

==================
WARNING: DATA RACE
Read at 0x0000005cb580 by main goroutine:
  main.read()
      /home/mero/tmp/x/x.go:15 +0xab
  main.main()
      /home/mero/tmp/x/x.go:26 +0x99

Previous write at 0x0000005cb580 by goroutine 7:
  main.increase()
      /home/mero/tmp/x/x.go:11 +0x54
  main.main.func1()
      /home/mero/tmp/x/x.go:21 +0x30
  main.main.func2()
      /home/mero/tmp/x/x.go:24 +0x3e

Goroutine 7 (running) created at:
  main.main()
      /home/mero/tmp/x/x.go:19 +0x8e
==================
4
Found 1 data race(s)
exit status 66
 
Go version is
go version go1.18 linux/amd64

So, I don't really understand why you think the race detector can't detect that race.


Thanks to Rust on emphasizing the single entrance to any variable,  I realized this possibility and have to add sync.Mutex to both functions.

What is your opinion?
 
Best Regards,
  Zhaoxun

--
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/5c6ae730-36a7-46ce-abb9-ea8d24da601bn%40googlegroups.com.

Zhaoxun Yan

unread,
Apr 30, 2022, 2:12:42 AM4/30/22
to golang-nuts
package main

import "time"
import "fmt"

var index int64

func increase(){
  index++
}

func read(){
  fmt.Println(index)
}

func main(){
   go func(N int){
     for i:=0; i < N; i++{
        increase()
        time.Sleep(500 * time.Millisecond)
     }
 }(5)
   time.Sleep(2 * time.Second)
   read()
}


Zhaoxun Yan

unread,
Apr 30, 2022, 2:18:55 AM4/30/22
to golang-nuts
Hi Axel!

My project is in a folder.
So actually the best way to mimic the situation is to put this file in a folder.
And then in that folder you run:
# go build -race
Nothing happens, at least in my go1.15
It did mention the race condition with `go run -race [filename]`
$ go run -race race.go
==================
WARNING: DATA RACE
Read at 0x0000006489c0 by main goroutine:
  main.read()
      /home/zxun/src/race.go:13 +0x6d
  main.main()
      /home/zxun/src/race.go:24 +0x5d

Previous write at 0x0000006489c0 by goroutine 7:
  main.increase()
      /home/zxun/src/race.go:9 +0x64
  main.main.func1()
      /home/zxun/src/race.go:19 +0x38


Goroutine 7 (running) created at:
  main.main()
      /home/zxun/src/race.go:17 +0x4f
==================
5
Found 1 data race(s)


Do you know the syntax to detect race condition for a whole folder of codes, instead of one file?
Thanks.
  Zhaoxun

Zhaoxun Yan

unread,
Apr 30, 2022, 2:21:34 AM4/30/22
to golang-nuts
go build -race
go build -race .

Either would not detect race condition for the whole project (folder).

Dan Kortschak

unread,
Apr 30, 2022, 2:22:26 AM4/30/22
to golan...@googlegroups.com
On Fri, 2022-04-29 at 23:18 -0700, Zhaoxun Yan wrote:
> And then in that folder you run:
> # go build -race
> Nothing happens, at least in my go1.15

The race detector needs to run to detect data races; it's not a static
analysis tool.

So if you execute the binary that you built with `go build -race` you
should see the race report.

Dan


Axel Wagner

unread,
Apr 30, 2022, 2:24:08 AM4/30/22
to Dan Kortschak, golang-nuts
Also, Go 1.15 is real old at this point and for these kinds of tests, I would recommend first updating to the latest stable version (which is Go 1.18).

--
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.

Zhaoxun Yan

unread,
Apr 30, 2022, 2:29:11 AM4/30/22
to golang-nuts
Hi Dan!

I did as you told, but go build -race still not functions:
zxun@zxun-virtual:~/src/race2$ go build
zxun@zxun-virtual:~/src/race2$ ls
race2  race.go
zxun@zxun-virtual:~/src/race2$ go build -race race2
zxun@zxun-virtual:~/src/race2$ go run -race race.go

==================
WARNING: DATA RACE
Read at 0x0000006489c0 by main goroutine:
  main.read()
      /home/zxun/src/race2/race.go:13 +0x6d
  main.main()
      /home/zxun/src/race2/race.go:24 +0x5d


Previous write at 0x0000006489c0 by goroutine 7:
  main.increase()
      /home/zxun/src/race2/race.go:9 +0x64
  main.main.func1()
      /home/zxun/src/race2/race.go:19 +0x38


Goroutine 7 (running) created at:
  main.main()
      /home/zxun/src/race2/race.go:17 +0x4f

==================
5
Found 1 data race(s)
exit status 66

Dan Kortschak

unread,
Apr 30, 2022, 2:44:45 AM4/30/22
to golan...@googlegroups.com
On Fri, 2022-04-29 at 23:29 -0700, Zhaoxun Yan wrote:
> Hi Dan!
>
> I did as you told, but go build -race still not functions:
> zxun@zxun-virtual:~/src/race2$ go build
> zxun@zxun-virtual:~/src/race2$ ls
> race2 race.go
> zxun@zxun-virtual:~/src/race2$ go build -race race2
> zxun@zxun-virtual:~/src/race2$ go run -race race.go

Try this:

./race2


Zhaoxun Yan

unread,
Apr 30, 2022, 3:01:46 AM4/30/22
to Axel Wagner, golang-nuts
Yes, you are correct.

Thanks a lot!

  Zhaoxun

Marvin Renich

unread,
Apr 30, 2022, 12:18:11 PM4/30/22
to golan...@googlegroups.com
* Zhaoxun Yan <yan.z...@gmail.com> [220430 02:29]:
> Hi Dan!
>
> I did as you told, but go build -race still not functions:

No, Dan said you must build with -race and then execute the output from
the build:

$ go build race race2
$ ./race2

What Dan was saying is that «go build -race» does _not_ detect races
during the build process, but produces an executable that contains the
race detector built-in, so that when you invoke the executable, any
races will be detected.

> zxun@zxun-virtual:~/src/race2$ go build
> zxun@zxun-virtual:~/src/race2$ ls
> race2 race.go
> zxun@zxun-virtual:~/src/race2$ go build -race race2
> zxun@zxun-virtual:~/src/race2$ go run -race race.go
> ==================
> WARNING: DATA RACE
[snip]

Zhaoxun Yan

unread,
May 1, 2022, 1:49:53 AM5/1/22
to golang-nuts
Hi Marvin!

  I am sure it did not detect race immediately at least in my project, which has similar global variable race conditions, but in a more subtle way .

  For example, the checking of one global variable is from an incoming message from a remote host, while the changing of the global variable is from a crontask. They have a possibility to collide, but my race build did not crash because of it yet.

Zhaoxun

Dan Kortschak

unread,
May 1, 2022, 2:47:12 AM5/1/22
to golan...@googlegroups.com
On Sat, 2022-04-30 at 22:49 -0700, Zhaoxun Yan wrote:
> I am sure it did not detect race immediately at least in my
> project, which has similar global variable race conditions, but in a
> more subtle way .
>
> For example, the checking of one global variable is from an
> incoming message from a remote host, while the changing of the global
> variable is from a crontask. They have a possibility to collide, but
> my race build did not crash because of it yet.

You have not confirmed that you are running the executable that was
built with the race detector.

However, yes it is entirely possible that the race detector can fail to
detect a potential race condition (see "How it works" in the Go blog
post that introduced it https://go.dev/blog/race-detector). This is
because it is not a static analysis tool. If your race is infrequent it
is possible for the sequence of concurrent reads and writes to not
happen during an execution.

If you are confident that there is a potential race condition in your
code, you can either fix it or attempt to increase the frequency of the
raciness and make yourself satisfied that it is there with the race
detector and then fix it.

Dan


Reply all
Reply to author
Forward
0 new messages