现象
相同代码在MacOS 13.3下与CentOS 6.5下运行结果不同。
问题代码
// 这段代码是封装了一个MySQL Client,对传入的host、user、port等参数做处理
// 这里起一个协程监听singnal传给子进程,保证MySQL Clinet能够正常监听singal
go func() {
for {
sig := <-sc
switch sig {
case syscall.SIGINT:
// MySQL Clinet会通过stdin监听SIGINT,再次传入会造成两次kill
// proc.Signal(syscall.SIGINT)
default:
err := proc.Signal(sig)
if err != nil {
Error.Fatalln(err)
}
}
}
}()
本来这段代码一开始Debug正常,也打成包在线上用了一段时间了。最近想给它添加点新功能,结果本地编译运行的时候就panic了。
Panic
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x40886ce]
goroutine 18 [running]:
os.(*Process).signal(0x0, 0x428a880, 0xc420132000, 0x0, 0x0)
/usr/local/go/src/os/exec_unix.go:56 +0x2e
os.(*Process).Signal(0x0, 0x428a880, 0xc420132000, 0x0, 0x0)
/usr/local/go/src/os/exec.go:129 +0x3f
main.main.func1(0xc420072240, 0xc42000e058)
/Users/Lepx/work/code/go/src/ku/ku.go:64 +0x80
created by main.main
/Users/Lepx/work/code/go/src/ku/ku.go:56 +0x33d
根据painc信息往下找可以看到是这段代码出的问题
func (p *Process) signal(sig Signal) error {
if p.Pid == -1 { //这里就是 /usr/local/go/src/os/exec_unix.go:56
return errors.New("os: process already released")
}
if p.Pid == 0 {
return errors.New("os: process not initialized")
}
p.sigMu.RLock()
defer p.sigMu.RUnlock()
if p.done() {
return errFinished
}
s, ok := sig.(syscall.Signal)
if !ok {
return errors.New("os: unsupported signal type")
}
if e := syscall.Kill(p.Pid, s); e != nil {
if e == syscall.ESRCH {
return errFinished
}
return e
}
return nil
}
然而这段代码拉到CentOS上编译运行就正常。
第一次遇到Golang相同代码在不同环境下编译运行状态不一致的问题,不知道这是不是一个bug。
这个问题目前在1.9.2与1.10上都有发现。
有疑问加站长微信联系(非本文作者))

明显是proc空指针造成的,看到
os.(*Process).Signal(0x0, 0x428a880, 0xc420132000, 0x0, 0x0)
第一个参数了吗?0代表对象是空指针,好好检查下代码看是不是有漏处理的错误造成的空指针。上层能接收的错误都接收了,同样的代码拿到Centos编译就没问题。
贴代码,不过我估计多半是构造proc变量的时候某些错误你没有检查造成的,比如要执行的MySQL client不存在