Skip to content
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: race in getitab (itab.init) #31419

cherrymui opened this issue Apr 11, 2019 · 1 comment

runtime: race in getitab (itab.init) #31419

cherrymui opened this issue Apr 11, 2019 · 1 comment


Copy link

@cherrymui cherrymui commented Apr 11, 2019

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

tip (3cb92fc)

Does this issue reproduce with the latest release?


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

darwin/amd64, also linux/amd64

What did you do?

package main

type T int

func (t T) M() {}

type I interface {

var t T
var e interface{} = &t
var ok = false
var ch = make(chan int)

func main() {
	_, ok = e.(I) // populate itab cache with a false result

	go f() // get itab in a loop

	var i I
	for k := 0; k < 10000; k++ {
		i, ok = e.(I) // read the cached itab
		if ok {
			println("iteration", k, "i =", i, "&t =", &t)
			panic("conversion succeeded")

func f() {
	for i := 0; i < 10000; i++ {
	ch <- 1

func f1() {
	defer func() {
		err := recover()
		if err == nil {
			panic("did not panic")
	i := e.(I) // triggers itab.init, for getting the panic string
	_ = i

What did you expect to see?

Not panic.

We do conversion of e (containing &t) to I concurrently, one with ",ok" form (in f1), one without (in main). T doesn't implement I, so the conversion should fail, and the program should not panic.

What did you see instead?


$ go run i.go
iteration 2778 i = (0x1161008,0x10ddc98) &t = 0x10ddc98
panic: conversion succeeded

goroutine 1 [running]:
	/tmp/i.go:27 +0x1a2
exit status 2
$ go run i.go
iteration 1681 i = (0x1161008,0x10ddc98) &t = 0x10ddc98
panic: conversion succeeded

goroutine 1 [running]:
	/tmp/i.go:27 +0x1a2
exit status 2

After some iterations, the conversion in main succeeded, with an I interface containing an &t, which is bad.

I think what happens here is:

  • In the first conversion (early in main), we populate the itab cache with a false result.
  • In f1, we get the same itab from the cache. As this is not ",ok" form, getitab calls m.init to find out what method is missing for the panic message. m.init writes[0] to T.M's code pointer as it sees the M method. Before return it sets[0] = 0 as it couldn't find the M2 method. There is a small window that[0] is not 0.
  • In the loop in main, we get the same itab from the cache, check its[0] field in getitab. If this happens in the middle of the window that[0] is not 0, it thinks the conversion succeeded.

I think we can fix this by not setting[0] immediately when we find the first method. Instead, store the code pointer in a variable, and set[0] only after we know the conversion succeeds. Will send a fix.

Found this while I'm porting itab caching to gccgo.

cc @aclements @randall77

Copy link

@gopherbot gopherbot commented Apr 11, 2019

Change mentions this issue: runtime: set[0] only on successful conversion

@gopherbot gopherbot closed this in 8d86ef2 Apr 11, 2019
@golang golang locked and limited conversation to collaborators Apr 10, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants
You can’t perform that action at this time.