Page 252 - 《软件学报》2026年第3期
P. 252
李清伟 等: Go 语言程序的内存性能与安全问题实证研究 1215
● N1: 指针使用前没有检查是否为空. 在该类别中, 根据该问题发生的上下文可分为如下 4 小类, 模式如代码 11
所示.
代码 11. N1: 指针使用前没有检查是否为空问题模式.
1. // N1-1: cockroachdb/cockroach/issues/48092
2. asString = GetAString() // may return nil
3. + if asString == nil { return }
4. parse(*asString) // as String not checked for nil
5. // N1-2: milvus-io/milvus/issues/17823
6. // ptr not checked for nil
7. − return ptr.GetState() != someState && ...
8. + return ptr != nil && ptr.GetState() != someState && ...
9. // N1-3: milvus-io/milvus/issues/5333
10. func getID() (ptr *Meta, err error) {
11. // ptr is notinitialized
12. + ... // initialize ptr
13. ptr.ID = ...
14. ...
15. }
16. // N1-4: milvus-io/milvus/issues/31495
17. if len(GetObj2ByObj1(obj1)) == 0 { continue }
18. obj2 = GetObj2byObj1AndObj3(obj1, obj3)
19. + if obj2 == nil { continue }
20. obj2.field // obj2 can still be nil
N1-1: 未对函数调用返回的指针进行空值检查. 代码 11 中第 1–4 行展示了 cockroach 的 Issue#48092 [56] 的代码
简化, 其中, asString 是函数调用返回的指针. 当 asString 为空时, 编译器生成的运行时检测代码会发现空指针并导
致提前崩溃. 虽然这种运行时检查避免了程序继续执行, 防止了未定义行为, 但它实际上可以通过静态分析工具或
者编译器的编译时检查进行提前检测, 提前发现部分空指针解引用问题. 尽管如此, 表 11 中仍有 6 条因未检查函
数返回指针是否为空而导致崩溃的 Issues.
N1-2: 在条件表达式中使用指针前未进行空值检查. 代码 11 中第 5–8 行展示了 milvus 的 Issue#17823 [57] 的代
码简化. 其中, ptr 在未检查是否为空的情况下就直接进行了方法调用, 导致崩溃.
N1-3: 指针变量在声明后未初始化就直接使用. 代码 11 中第 9–15 行展示了 milvus 的 Issue#5333 [58] 的代码简
化, 由于返回值变量 ptr 未初始化就进行解引用访问操作 ptr.ID, 导致程序运行时崩溃.
N1-4: 使用指针前非空判断条件不充分. 代码 11 中第 16–20 行展示了 milvus 的 Issue#31495 [59] 的代码简化.
由于 len( ...) == 0 的条件判断不等价于 obj2 不为空, 导致在进行解引用访问 obj2.field 时发生崩溃.
● N2. 某些操作的执行取决于指针是否为 nil 指针. 是否为 nil 可以作为是否执行与指针相关操作的条件. 在
某些情况下, 指针应该被置为 nil 以防止非法操作被调用. 代码 12 展示了修复代码, 当发生错误时, d.serializer 被
置为空, 以防止后续对非法操作的调用.
● N3. 杂项. 除了上述提到的简单模式之外, 在 21 条与无效内存地址或空指针解引用相关的 Issues 中, 有 10
条属于该范畴. 由于这些问题的修复规模较大并且需要较强的领域知识, 故无法推断出导致问题的核心原因.

