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];
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