返回顶部
g

golang-safetyGo安全编码

Defensive Golang coding to prevent panics, silent data corruption, and subtle runtime bugs. Use whenever writing or reviewing Go code that involves nil-prone types (pointers, interfaces, maps, slices, channels), numeric conversions, resource lifecycle (defer in loops), or defensive copying. Also triggers on questions about nil panics, append aliasing, map concurrent access, float comparison, or zero-value design.

作者: admin | 来源: ClawHub
源自
ClawHub
版本
V 1.1.1
安全检测
已通过
121
下载量
免费
免费
0
收藏
概述
安装方式
版本历史

golang-safety

技能名称: golang-safety

角色定位: 你是一名防御性Go工程师。你将每一个关于nil、容量和数值范围的未经测试的假设,都视为潜在的崩溃隐患。

Go 安全性:正确性与防御性编码

防止程序员错误——在正常(非对抗性)代码中出现的bug、panic和静默数据损坏。安全性处理攻击者;安全性处理我们自己。

最佳实践总结

  1. 1. 当类型集合已知时,优先使用泛型而非 any —— 编译器能捕获类型不匹配,而非在运行时panic
  2. 始终对类型断言使用逗号-ok模式 —— 裸断言在类型不匹配时会panic
  3. 接口中的类型化nil指针不等于 == nil —— 类型描述符使其非nil
  4. 向nil map写入会panic —— 使用前务必初始化
  5. append 可能重用底层数组 —— 如果容量允许,两个切片会共享内存,静默地相互破坏
  6. 从导出函数返回防御性副本 —— 否则调用者会修改你的内部状态
  7. defer 在函数退出时执行,而非循环迭代时 —— 将循环体提取到一个函数中
  8. 整数转换会静默截断 —— int64 转 int32 会无错误地回绕
  9. 浮点数运算不精确 —— 使用epsilon比较或 math/big
  10. 设计有用的零值 —— nil map字段在首次写入时panic;使用惰性初始化
  11. 使用 sync.Once 进行惰性初始化 —— 即使在并发下也能保证只执行一次

Nil 安全性

与nil相关的panic是Go中最常见的崩溃。

nil接口陷阱

接口存储(类型,值)。只有当两者都为nil时,接口才为 nil。返回一个类型化的nil指针会设置类型描述符,使其非nil:

go
// ✗ 危险 — interface{type: *MyHandler, value: nil} 不等于 nil
func getHandler() http.Handler {
var h *MyHandler // nil指针
if !enabled {
return h // interface{type: *MyHandler, value: nil} != nil
}
return h
}

// ✓ 良好 — 显式返回 nil
func getHandler() http.Handler {
if !enabled {
return nil // interface{type: nil, value: nil} == nil
}
return &MyHandler{}
}

nil map、切片和channel的行为

类型从nil读取向nil写入nil的Len/Cap对nil进行Range
Map零值panic00次迭代
切片
panic (索引) | panic (索引) | 0 | 0次迭代 | | Channel | 永久阻塞 | 永久阻塞 | 0 | 永久阻塞 |

go
// ✗ 糟糕 — nil map在写入时panic
var m map[string]int
m[key] = 1

// ✓ 良好 — 初始化或在方法中惰性初始化
m := make(map[string]int)

func (r *Registry) Add(name string, val int) {
if r.items == nil { r.items = make(map[string]int) }
r.items[name] = val
}

关于nil接收者、泛型中的nil以及nil接口性能,请参阅 Nil 安全性深度探讨

切片与Map安全性

切片别名——append陷阱

如果容量允许,append 会重用底层数组。这样两个切片会共享内存:

go
// ✗ 危险 — a 和 b 共享底层数组
a := make([]int, 3, 5)
b := append(a, 4)
b[0] = 99 // 也会修改 a[0]

// ✓ 良好 — 完整切片表达式强制新分配
b := append(a[:len(a):len(a)], 4)

Map并发访问

Map绝不能被并发访问——同步原语请参见 samber/cc-skills-golang@golang-concurrency。

关于range陷阱、子切片内存保留以及 slices.Clone/maps.Clone,请参阅 切片与Map深度探讨

数值安全性

隐式类型转换会静默截断

go
// ✗ 糟糕 — 如果 val > math.MaxInt32 (30亿变成-12.9亿),会静默回绕
var val int64 = 3000000_000
i32 := int32(val) // -1294967296 (静默回绕)

// ✓ 良好 — 在转换前检查
if val > math.MaxInt32 || val < math.MinInt32 {
return fmt.Errorf(值 %d 溢出 int32, val)
}
i32 := int32(val)

浮点数比较

go
// ✗ 糟糕 — 浮点数运算不精确
0.1+0.2 == 0.3 // false

// ✓ 良好 — 使用epsilon比较
const epsilon = 1e-9
math.Abs((0.1+0.2)-0.3) < epsilon // true

除零错误

整数除以零会panic。浮点数除以零会产生 +Inf、-Inf 或 NaN。

go
func avg(total, count int) (int, error) {
if count == 0 {
return 0, errors.New(除零错误)
}
return total / count, nil
}

关于整数溢出作为安全漏洞,请参见 samber/cc-skills-golang@golang-security 技能部分。

资源安全性

循环中的defer——资源累积

defer 在函数退出时执行,而非循环迭代时。资源会一直累积直到函数返回:

go
// ✗ 糟糕 — 所有文件保持打开状态直到函数返回
for _, path := range paths {
f, _ := os.Open(path)
defer f.Close() // 延迟到函数退出
process(f)
}

// ✓ 良好 — 提取到函数,这样defer每次迭代都会执行
for _, path := range paths {
if err := processOne(path); err != nil { return err }
}
func processOne(path string) error {
f, err := os.Open(path)
if err != nil { return err }
defer f.Close()
return process(f)
}

Goroutine泄漏

→ 关于goroutine生命周期和泄漏预防,请参见 samber/cc-skills-golang@golang-concurrency。

不可变性与防御性拷贝

返回切片/map的导出函数应该返回防御性副本。

保护结构体内部状态

go
// ✗ 糟糕 — 导出的切片字段,任何人都可以修改
type Config struct {
Hosts []string
}

// ✓ 良好 — 未导出字段,通过返回副本的访问器访问
type Config struct {
hosts []string
}

func (c *Config) Hosts() []string {
return slices.Clone(c.hosts)
}

初始化安全性

零值设计

设计类型使得 var x MyType 是安全的——防止忘记初始化的bug:

go
var mu sync.Mutex // ✓ 零值可用
var buf bytes.Buffer // ✓ 零值可用

// ✗ 糟糕 — nil map在写入时panic
type Cache struct { data map[string]any }

使用sync.Once进行惰性初始化

go
type DB struct {
once sync.Once
conn *sql.DB
}

func (db DB) connection() sql.DB {
db.once.Do(func() {
db.conn, _ = sql.Open(postgres, connStr)
})
return db.conn
}

init() 函数陷阱

→ 关于为何应避免使用 init() 而使用显式构造函数,请参见 samber/cc-skills-golang@golang-design-patterns。

使用Linter强制执行

许多安全性陷阱可以通过linter自动捕获:errcheck、forcetypeassert、nilerr、govet、staticcheck。关于配置和使用,请参见 samber/cc-skills-golang@golang-linter 技能。

交叉引用

  • - → 关于并发访问模式和同步原语,请参见 samber/cc-skills-golang@golang-concurrency 技能
  • → 关于切片/map内部机制、容量增长和container/包,请参见 samber/cc-skills-golang@golang-data-structures 技能
  • → 关于nil错误接口陷阱,请参见 samber/cc-skills-golang@golang-error-handling 技能
  • → 关于安全相关的安全问题(内存安全、整数

标签

skill ai

通过对话安装

该技能支持在以下平台通过对话安装:

OpenClaw WorkBuddy QClaw Kimi Claude

方式一:安装 SkillHub 和技能

帮我安装 SkillHub 和 golang-safety-1776057856 技能

方式二:设置 SkillHub 为优先技能安装源

设置 SkillHub 为我的优先技能安装源,然后帮我安装 golang-safety-1776057856 技能

通过命令行安装

skillhub install golang-safety-1776057856

下载

⬇ 下载 golang-safety v1.1.1(免费)

文件大小: 20.69 KB | 发布时间: 2026-4-14 14:01

v1.1.1 最新 2026-4-14 14:01
- Bumped version to 1.1.1 in metadata.
- Added a new evaluation config file: evals/evals.json.

Archiver·手机版·闲社网·闲社论坛·羊毛社区· 多链控股集团有限公司 · 苏ICP备2025199260号-1

Powered by Discuz! X5.0   © 2024-2025 闲社网·线报更新论坛·羊毛分享社区·http://xianshe.com

p2p_official_large
返回顶部