这是什么原因导致Go中的段错误(segfault)?

huangapple go评论90阅读模式
英文:

What is causing this segfault in Go?

问题

背景:由于Go语言内置的JSON编组器在给定omitempty标志时不会检查零值,因此我们尝试在需要干净地编组为JSON的结构中使用*time.Time而不是time.Time。但是,这样做的问题显然是我们在使用它时需要非常小心地检查它是否为nil。我们注意到的一件事是,在一个设置包含结构的创建时间的函数中,当我们在数据库中检查JSON时,所有的时间都完全相同,精确到纳秒。

为了检查这是否与指针有关还是因为系统性能非常好,我做了这个测试

package main

import (
	"fmt"
	"time"
)

type Timekeeper struct {
	myTime *time.Time
}

func main() {
	
	t := make([]Timekeeper, 100)
	var now time.Time
	for _, v := range t {
		now = time.Now()
		v.myTime = &now
		time.Sleep(1 * time.Second)
	}
	
	for i, times := range t {
		fmt.Printf("Timekeeper %s time: %s.", i, times.myTime.Format(time.RFC3339Nano))
	}
	
}

但是它一直产生以下恐慌:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0xffffffff addr=0x0 pc=0x20314]

goroutine 1 [running]:
panic(0x112c00, 0x1040a038)
	/usr/local/go/src/runtime/panic.go:500 +0x720
main.main()
	/tmp/sandbox675251439/main.go:23 +0x314

Program exited.

我猜这与指针被不断重新分配有关,但我有一个心理障碍,无法确定问题的具体原因。有人能解释一下这里发生了什么吗?

英文:

Background: Because Go's inbuilt JSON marshaller doesn't check for zero values when given the omitempty flag, we're trying using *time.Time rather than time.Time in structs that need to be marshalled cleanly to JSON. The problem with this is obviously we need to be very careful to always check it is not nil when using it. One thing we did notice was in a function that sets a creation time on the encompassing struct, when we checked the JSON in the database all of the times were exactly the same, down to the nanosecond.

To check whether this was something to do with the pointer or just because the system was performing very well, I made this test:

package main

import (
	"fmt"
	"time"
)

type Timekeeper struct {
	myTime *time.Time
}

func main() {
	
	t := make([]Timekeeper, 100)
	var now time.Time
	for _, v := range t {
		now = time.Now()
		v.myTime = &now
		time.Sleep(1 * time.Second)
	}
	
	for i, times := range t {
		fmt.Printf("Timekeeper %s time: %s.", i, times.myTime.Format(time.RFC3339Nano))
	}
	
}

but it keeps producing this panic:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0xffffffff addr=0x0 pc=0x20314]

goroutine 1 [running]:
panic(0x112c00, 0x1040a038)
	/usr/local/go/src/runtime/panic.go:500 +0x720
main.main()
	/tmp/sandbox675251439/main.go:23 +0x314

Program exited.

I'm assuming this is something to do with the pointer being constantly reassigned to, but I've got a mental block going on and I can't figure out exactly what the issue is. Can someone please explain what is happening here?

答案1

得分: 6

在你的循环中,你复制了每个Timekeeper的值。改为这样做:

for i := range t {
    now := time.Now()
    t[i].myTime = &now
}

这样,每个TimekeepermyTime字段都会指向一个独立的time.Time对象。

英文:

In your loop you copy every Timekeeper value. Do this instead:

for i := range t {
    now = time.Now()
    t[i].myTime = &now
}

huangapple
  • 本文由 发表于 2016年12月21日 19:04:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/41261284.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定