You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go字符串拼接触发nil指针panic问题及原因咨询

Go字符串拼接触发nil指针panic问题分析

问题背景

在Go函数执行字符串拼接时触发nil指针解引用panic,仅出现一次,进程重启后恢复。相关代码及错误信息如下:

代码片段

646: func (m *LineModule) getKey(timestamp int64, log *model.Log,
647:    loc model.LocationInfo, retMap map[int64]interface{}) {
648:    timeNow := time.Now().Local()
649:    project := util.GetProjectName(log.Flag, log.CustomInfo)
650:    protocol := util.GetProtocol(log, m.IDMap)
651:    version := util.GetVersion(log, m.IDMap)
652:    key := log.Server + log.Level + log.Host + loc.Region + loc.Isp + loc.Country +
653:       strconv.Itoa(log.Tag) + log.ONT + project + "_" + protocol + version   // panic触发点

错误信息

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

goroutine 709 [running]:
data/module.(*LineModule).getKey(0xc001bf4500, 0x55ad1f7d8aa0, 0xc0328ef680, {{0x55ad1edf555e, 0x2}, {0xc0337ad207, 0x6}, {0xc001558ed6, 0x6}}, 0xc001562000)
        /data/module/line_module.go:653 +0x3ec
data/module.(*LineModule).calc(0xc02f250f90, {0x55ad1f2b9478, 0xc0328ef680}, 0x0)
        /data/module/line_module.go:643 +0x247
data/module.(*LineModule).run(0xc001bf4500)
        /data/module/line_module.go:236 +0x126
created by data/module.(*LineModule).Init.func1
        /data/module/line_module.go:180 +0x9b

问题分析

1. panic的根源

panic并非因为调用getKey时log初始为nil(否则第649行访问log.Flag就会直接panic),更大概率是并发竞态条件导致:

  • 调用getKey时log指针是非nil的,前几行(649-651)能正常访问log的字段;
  • 在执行到第653行之前,其他goroutine异步将log指针修改为nil,此时访问log.Tag或log.ONT就会触发nil指针解引用panic;
  • 另一种可能是model.Log的某个字段(比如ONT)是指针类型,被其他goroutine置为nil,访问该字段时触发panic。

2. 为什么第649行未触发panic

因为函数执行初期log指针是非nil的,前几行代码能正常访问log的成员。只有当后续代码执行时,log指针被外部goroutine修改为nil,才会在第653行触发panic。这种场景完全依赖goroutine的调度时机,属于偶发的竞态问题。

3. 为什么问题仅出现一次

竞态条件的触发需要极端巧合的调度时机:多个goroutine的执行节奏刚好凑成“前几行用log时非nil,到第653行时log被置为nil”。进程重启后,系统负载、goroutine调度顺序发生变化,不再满足这个巧合条件,因此问题不再复现。

解决方案

  • 前置nil检查:在函数开头添加if log == nil { return }(或根据业务逻辑做兜底处理),避免后续访问nil指针;
  • 保证并发安全:如果log对象会被多个goroutine共享修改,需使用互斥锁(sync.Mutex)保护访问,或者改为传递model.Log的值而非指针;
  • 检查字段类型:确认model.Log的所有字段是否为值类型,若存在指针类型字段,同样要保证其访问和修改的并发安全性。

内容的提问来源于stack exchange,提问作者Michael96

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 23:55:18