【解决一个小问题】golang 的 `-race`选项导致 unsafe代码 panic

这篇具有很好参考价值的文章主要介绍了【解决一个小问题】golang 的 `-race`选项导致 unsafe代码 panic。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!

  • cnblogs博客
  • zhihu
  • Github
  • 公众号:一本正经的瞎扯
    【解决一个小问题】golang 的 `-race`选项导致 unsafe代码 panic

为了提升性能,使用 unsafe 代码来重构了凯撒加密的代码。代码如下:

const (
	lowerCaseAlphabet = "abcdefghijklmnopqrstuvwxyz"
	upperCaseAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
)

var (
	lowerCaseAlphabetArr     = []byte(lowerCaseAlphabet)
	upperCaseAlphabetArr     = []byte(upperCaseAlphabet)
	tableOflowerCaseAlphabet = unsafe.Pointer(&lowerCaseAlphabetArr[0])
	tableOfupperCaseAlphabe  = unsafe.Pointer(&upperCaseAlphabetArr[0])
)

// CaesarFastEncode fast version
func CaesarFastEncode(in []byte, out []byte, rot int) {
	start := unsafe.Pointer(&in[0])
	target := unsafe.Pointer(&out[0])
	for i := 0; i < len(in); i++ {
		c := *((*byte)(start))
		if c == '.' {
			*((*byte)(target)) = '='
		} else if c >= 'a' && c <= 'z' {
			idx := (int(26+(c-'a')) + rot) % 26
			*((*byte)(target)) = *((*byte)(unsafe.Pointer(uintptr(tableOflowerCaseAlphabet) + uintptr(idx))))
		} else if c >= 'A' && c <= 'Z' {
			idx := (int(26+(c-'A')) + rot) % 26
			*((*byte)(target)) = *((*byte)(unsafe.Pointer(uintptr(tableOfupperCaseAlphabe) + uintptr(idx))))
		} else {
			*((*byte)(target)) = *((*byte)(start))
		}
		start = unsafe.Pointer(uintptr(start) + uintptr(1))
		target = unsafe.Pointer(uintptr(target) + uintptr(1))
	}
}

命令行运行go test 的时候发现,代码中发生了 panic。而我直接在 vscode 中通过快捷键运行又是正常的。
错误信息如下:

fatal error: checkptr: pointer arithmetic result points to invalid allocation

goroutine 6 [running]:
runtime.throw({0x104936d70?, 0x10410270c?})
        /opt/homebrew/Cellar/go/1.20.4/libexec/src/runtime/panic.go:1047 +0x40 fp=0xc0001e5a60 sp=0xc0001e5a30 pc=0x104132280
runtime.checkptrArithmetic(0xc0001e5ac8?, {0xc0001e5b00, 0x1, 0x0?})
        /opt/homebrew/Cellar/go/1.20.4/libexec/src/runtime/checkptr.go:69 +0xac fp=0xc0001e5a90 sp=0xc0001e5a60 pc=0x1041028cc
cryptoutil.CaesarFastEncode({0xc000216cc4, 0xc, 0xc0001e5b68?}, {0xc000232a02, 0x1fe, 0x104f3ee00?}, 0x3)
        /Users/ahfuzhang/code/golang/xxx/caesar.go:83 +0x84 fp=0xc0001e5b20 sp=0xc0001e5a90 pc=0x104570a74

进一步发现,命令行中有个不一样的选项:

go test -v -cover -race ./...

去掉 -race选项后,一切正常。

搜索看到了这篇文章:《Go 1.15中值得关注的几个变化》

Go 1.14版本中,Go编译器在被传入-race和-msan的情况下,默认会执行-d=checkptr,即对unsafe.Pointer的使用进行合法性检查。-d=checkptr主要检查两项内容:

•当将unsafe.Pointer转型为*T时,T的内存对齐系数不能高于原地址的;

•做完指针算术后,转换后的unsafe.Pointer仍应指向原先Go堆对象

由此可见,循环做完后,最后一行必然导致指针超出原来的 buffer。
为了符合 golang 的规范,微调了代码后通过:

// CaesarFastEncode fast version
func CaesarFastEncode(in []byte, out []byte, rot int) {
	start := unsafe.Pointer(&in[0])
	end := uintptr(start) + uintptr(len(in)-1)
	target := (unsafe.Pointer(&out[0]))
	for {
		c := *((*byte)(start))
		if c == '.' {
			*((*byte)(target)) = '='
		} else if c >= 'a' && c <= 'z' {
			idx := (int(26+(c-'a')) + rot) % 26
			*((*byte)(target)) = *((*byte)(unsafe.Pointer(uintptr(tableOflowerCaseAlphabet) + uintptr(idx))))
		} else if c >= 'A' && c <= 'Z' {
			idx := (int(26+(c-'A')) + rot) % 26
			*((*byte)(target)) = *((*byte)(unsafe.Pointer(uintptr(tableOfupperCaseAlphabe) + uintptr(idx))))
		} else {
			*((*byte)(target)) = *((*byte)(unsafe.Pointer(start)))
		}
		if uintptr(start) >= end {
			break
		}
		start = unsafe.Pointer(uintptr(start) + uintptr(1))
		target = unsafe.Pointer(uintptr(target) + uintptr(1))
	}
}

由此看来,只要使用了 unsafe 代码,都应该加上-race选项。文章来源地址https://www.toymoban.com/news/detail-481217.html

到了这里,关于【解决一个小问题】golang 的 `-race`选项导致 unsafe代码 panic的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 解决git切换分支导致代码丢失的问题

    问题背景: ​ 因为本人手里有好几个不同的项目,当手里有正在做的项目,却被临时叫去修改另外一个项目,而此时又不想把现有的代码提交,于是就强制切换到了另外一个分支上。悲剧的事情发生了,再次切换回来的时候发现之前写的代码丢失了。 解决方法: ​ 本人使用

    2024年02月11日
    浏览(46)
  • CentOS下多网卡绑定多IP段时导致只有一个会通的问题解决

    CentOS下多网卡绑定多IP段时导致只有一个会通的问题解决 虚拟机配置多个网络地址,结果同时只能有一个ip是通的, 原因:Linux默认开启了反向路由检查导致的,比如说外面访问eth0的网卡,而网关在eth1上,又或者从eth0出的流量,而网关在eth1上,此时会检查到网关不在同一个

    2024年02月10日
    浏览(38)
  • seatunnel hive source 未设置分隔符导致多个字段合并成一个的问题定位解决

    seatunnel hive source 未设置分隔符导致多个字段没有切分全保存在一个字段中了,翻看源码发现分隔符是是通过delimiter设置的,只要设置这个delimiter=\\\",\\\"就可以了。 设置这个属性 delimiter=“,” 他的默认值是u0001,如果没有设置delimiter属性则会根据文件类型判断,如果是csv则使用”,”

    2024年02月16日
    浏览(51)
  • 【问题处理】GIT合并解决冲突后,导致其他人代码遗失的排查

    📕作者简介:战斧,从事金融IT行业,有着多年一线开发、架构经验;爱好广泛,乐于分享,致力于创作更多高质量内容 📗本文收录于 GIT 专栏,有需要者,可直接订阅专栏实时获取更新 📘高质量专栏 云原生、RabbitMQ、Spring全家桶 等仍在更新,欢迎指导 📙Zookeeper Redis ka

    2024年02月08日
    浏览(62)
  • 记录一个IDEA中使用GIT的严重BUG,导致测试分支合并到主分支,以及代码恢复解决方案

    在做项目时遇到了一个问题,就是不知道什么操作,无缘无故把test分支代码合并到了master,导致花了好长时间去恢复master分支的代码,所以研究了一下,到底是什么原因导致的这个问题 PS: 后来分析出来根本原因,确定这确实是IDEA的一个BUG,在下面会有详细描述 当我们在test分支时,

    2023年04月14日
    浏览(70)
  • 标准库unsafe:带你突破golang中的类型限制

    本文分享自华为云社区《突破语言golang中的类型限制》,作者:码乐。 在使用c语言编程时,常常因为类型的问题大伤脑筋,而其他语言比如java,python默认类型又是难以改变的,golang提供了一些方式用于喜欢hack的用户。 官方说明标准库 unsafe 包含绕过 Go 程序的类型安全的操

    2024年04月08日
    浏览(43)
  • Alibaba Java Coding Guidelines(阿里代码规范插件,并且解决IDEA版本,导致无法在线安装问题)

    为了让开发更加方便、更为规范,阿里巴巴基于手册内容,研发了一套自动化的代码规范检测插件Alibaba Java Coding Guidelines 。该插件在扫描代码后,将不符合规约的代码按Blocker/Critical/Major三个等级显示在下方,严重程度由高到低为:Blocker Critical Major,严重程度由高到低为:

    2024年03月15日
    浏览(57)
  • HIVE 3 使用 MR 引擎多表关联 (JOIN) 导致丢数的问题复现、问题根源及解决方案 (附代码)

    本文意图解决 HIVE 3 版本中使用 MR 作为运算引擎进行 JOIN 操作时导致的丢数情况。 Apache Hive 在 2.3 版本后宣布放弃维护 MapReduce 作为底层执行引擎,并转而使用 Tez 作为默认的查询引擎。但是由于 Tez 在大作业量和高并发时的严重性能问题,导致许多任务不得不继续使用 MapRe

    2024年02月13日
    浏览(36)
  • Visual studio解决‘scanf: This function or variable may be unsafe. 问题

    使用C语言的scanf函数在Visual Studio软件上运行会报如下错误: \\\'scanf: This function or variable may be unsafe. Consider using scanf s instead. To disable deprecation, use. CRT SECURE NO WARNINGS. See online help for details. 这个函数或变量可能是不安全的。请考虑使用扫描S。若要禁用弃用,请使用。CRT没有任何警

    2024年02月09日
    浏览(47)
  • Keil STM32配置SRAM启动并解决SRAM模式代码跑向中断向量表导致程序跑飞的问题

    STM32的Flash的可擦写次数在10000次,在学习或调试过程中为了延长Flash的寿命,将程序写入SRAM是一个很好的办法。在百度上找到的SRAM启动方法总有各种各样的问题,接下来我将会提供一个完整的思路给大家学会如何配置SRAM启动的环境。 这里用来演示的开发板是STM32F103C8T6 1. 在

    2024年02月03日
    浏览(56)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包