On Mon, Mar 9, 2020 at 9:16 AM Yuu LongXue <longxue...@gmail.com> wrote: > > Hi all, > > Slice is not thread safe for write operation if without lock, this is true > and I know this feature. but recently, I got a panic which caused by writing > a slice concurrently with out lock occasionally and I can't figure out why. > > ### the process as below: > 1. define a slice: var x []string > 2. append to x concurrently without lock in multi goroutines > 3. wait all goroutines to be done > 4. iterate the x slice, panic occurred when read some element with index > <strong>i (i > 0 && i < len(x)-1)</strong> in the x > > ### the question is: > In this case, the element with index 0 and index len(x) - 1 is ok to read, > but it exists a <strong>x[i](i > 0 && i < len(x)-1)</strong> that can't be > read and it will lead to panic[invalid memory address or nil pointer > dereference];
You have a race, so the behavior is undefined. One can only guess what went wrong. It is possible that you have a corrupt string in the slice, one with len>0 but with a nil backing array, because you have many goroutines writing to the same element of the slice, and you don't know which one wrote what in what order. > > I know that some data by the write operation missed, but how could the panic > occur? I have tried my best to know why, but I still can't figure out; > <strong>so could anyone tell me why the element in x has a invalid address? > maybe it was collected by gc or not initialized yet and why?<strong> > > ### code > ``` > func TestConcurrentWriteSlice(t *testing.T) { > // panic do not occurred for each running, so I repeat until it occurred > for i := 0; i < 100; i++ { > testConcurrentWriteSlice() > } > } > > func testConcurrentWriteSlice() { > var strs []string > > // write concurrently here > var wg sync.WaitGroup > for x := 0; x < 1000; x++ { > wg.Add(1) > go func() { > defer func() { wg.Done() }() > time.Sleep(2 * time.Second) > for i := 65; i < 91; i++ { > strs = append(strs, string(i)) > } > }() > } > wg.Wait() > > l := len(strs) > log.Printf("strs len: %v f=%v l=%v", l, strs[0], strs[l-1]) > for i := 0; i < l; i++ { > log.Printf("strs len=%v i=%v first=%v last=%v > ¤t[i]=%v", l, i, strs[0], strs[l-1], &strs[i]) > > // panic here > log.Printf("strs len=%v i=%v first=%v last=%v current=%v", l, > i, strs[0], strs[l-1], strs[i]) > } > } > ``` > > ### output log > ``` > 2020/03/09 14:39:08 strs len=2607 i=519 first=A last=Z > ¤t[i]=0xc000606070 > 2020/03/09 14:39:08 strs len=2607 i=519 first=A last=Z current= > 2020/03/09 14:39:08 strs len=2607 i=520 first=A last=Z > ¤t[i]=0xc000606080 > 2020/03/09 14:39:08 strs len=2607 i=520 first=A last=Z current= > 2020/03/09 14:39:08 strs len=2607 i=521 first=A last=Z > ¤t[i]=0xc000606090 > 2020/03/09 14:39:08 strs len=2607 i=521 first=A last=Z current= > 2020/03/09 14:39:08 strs len=2607 i=522 first=A last=Z > ¤t[i]=0xc0006060a0 > 2020/03/09 14:39:08 strs len=2607 i=522 first=A last=Z current= > 2020/03/09 14:39:08 strs len=2607 i=523 first=A last=Z > ¤t[i]=0xc0006060b0 > --- FAIL: TestConcurrentWriteSlice (19.72s) > panic: runtime error: invalid memory address or nil pointer dereference > [recovered] > panic: runtime error: invalid memory address or nil pointer > dereference > [signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x105aa93] > > goroutine 33 [running]: > testing.tRunner.func1(0xc0000d8100) > /usr/local/go/src/testing/testing.go:874 +0x3a3 > panic(0x1127f20, 0x12494b0) > /usr/local/go/src/runtime/panic.go:679 +0x1b2 > fmt.(*buffer).writeString(...) > /usr/local/go/src/fmt/print.go:82 > fmt.(*fmt).padString(0xc000082040, 0x0, 0x115ced0) > /usr/local/go/src/fmt/format.go:110 +0x8c > fmt.(*fmt).fmtS(0xc000082040, 0x0, 0x115ced0) > /usr/local/go/src/fmt/format.go:359 +0x61 > fmt.(*pp).fmtString(0xc000082000, 0x0, 0x115ced0, 0x76) > /usr/local/go/src/fmt/print.go:447 +0x131 > fmt.(*pp).printArg(0xc000082000, 0x111c3a0, 0xc00011ed80, 0x76) > /usr/local/go/src/fmt/print.go:698 +0x877 > fmt.(*pp).doPrintf(0xc000082000, 0x115b38e, 0x2c, 0xc0000c9ef8, 0x5, 0x5) > /usr/local/go/src/fmt/print.go:1030 +0x15b > fmt.Sprintf(0x115b38e, 0x2c, 0xc000840ef8, 0x5, 0x5, 0x1, 0xc00011ed80) > /usr/local/go/src/fmt/print.go:219 +0x66 > log.Printf(0x115b38e, 0x2c, 0xc000840ef8, 0x5, 0x5) > /usr/local/go/src/log/log.go:307 +0x53 > github.com/test/project/util.testConcurrentWriteSlice() > /Users/zhangqinxue/work/github/demo/go/project/util/slice_test.go:36 > +0x323 > github.com/test/project/util.TestConcurrentWriteSlice(0xc0000d8100) > /Users/zhangqinxue/work/github/demo/go/project/util/slice_test.go:12 > +0x2a > testing.tRunner(0xc0000d8100, 0x115caf0) > /usr/local/go/src/testing/testing.go:909 +0xc9 > created by testing.(*T).Run > /usr/local/go/src/testing/testing.go:960 +0x350 > ``` > > Thanks > > YUU > > -- > 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+unsubscr...@googlegroups.com. > To view this discussion on the web visit > https://groups.google.com/d/msgid/golang-nuts/122CE4C2-A82A-4819-BFBD-E6E98A71BF7F%40gmail.com. -- 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+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CAMV2Rqp-1%3D7MYg64vjKfCinOCQuhObCGba4NCBswx2AytTupzQ%40mail.gmail.com.