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


为了提升性能,使用 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选项。

【解决一个小问题】golang 的 `-race`选项导致 unsafe代码 panic的更多相关文章

  1. 解决 VS Code 中 golang.org 被墙导致的 Go 插件安装失败问题

    微软官方开发的 Go for Visual Studio Code 插件为 Go 语言 提供了丰富的支持.在 VS Code 中首次打开 Go 工作区后,VS Code 会自动检测当前开发环境为 Go ...

  2. 使用docker 解决一个小问题,你也可能用的到

    以前一直觉得docker是运维用的工具,或者devops 用的工具,一般人应该用不上,直到最近发现docker 还有另外一个妙用,不管是什么语言. 这几天开会网络特别不好,nodejs npm 仓库 ...

  3. eclipse_neon 的Spket 目录下只有一个Task Tags,没有其他的选项,导致没有办法添加提示文件! 添加sdk文件之后还是没有办法显示的解决办法

    问题解决办法: 将 spket-1.6.23的安装包里面的features  plugins 单独复制到D:\eclipse_neon\dropins 目录下,重启一下eclipse即可正常显示! 添 ...

  4. 如果公司里有上百个表要做触发器,如果手动写代码的话。很累,所以今天写了一个小程序,自动生成mysql的触发代码。

    <?php $dbname = 'test';//数据库 $tab1 = 'user'; //执行的表 $tab2 = 'user_bak'; //被触发的表 $conn = mysql_con ...

  5. 关于反射的一个小问题---.NetFrameWork版本不一样导致不同的系统的问题

    背景: 近期项目中用到发射,本人的电脑上是安装了.NetFrameWork 4.5,然后用着发射蛮顺溜的,啪啪,三下五除二,项目完成了,然后提交测试了,测试的电脑是虚拟机上安装了xp系统,然后.Net ...

  6. go的变量redeclare的问题,golang的一个小坑

    go的变量声明有几种方式: 1 通过关键字 var 进行声明 例如:var i int   然后进行赋值操作 i = 5 2 最简单的,通过符号 := 进行声明和赋值 例如: i:=5 golang会 ...

  7. linux下开发,解决cocos2d-x中编译出现的一个小问题, undefined reference to symbol &#39;pthread_create@@GLIBC_2.2.5&#39;

    解决cocos2d-x中编译出现的一个小问题 对于cocos2d-x 2.×中编译中,若头文件里引入了#include "cocos-ext.h",在进行C++编译的时候会遇到例如 ...

  8. golang中的选项模式

    索引 https://waterflow.link/articles/1663835071801 当我在使用go-zero时,我看到了好多像下面这样的代码: ... type ( // RunOpti ...

  9. 与大家分享robotium一个小问题。Test run failed:Instrumentation run failed due to 'java.lang.ClassNotFoundException'

    今天和大家分享robotium一个小问题. 我们在运行自已经搭好的框架时,有可能会出现一个找不到类的错误(如上图所示). 问题是重签名工具给出的activity有误,这时我们可以用Appt命令查看重签 ...

  10. 用struts2标签如何从数据库获取数据并在查询页面显示。最近做一个小项目,需要用到struts2标签从数据库查询数据,并且用迭代器iterator标签在查询页面显示,可是一开始,怎么也获取不到数据,想了许久,最后发现,是自己少定义了一个变量,也就是var变量。

    最近做一个小项目,需要用到struts2标签从数据库查询数据,并且用迭代器iterator标签在查询页面显示,可是一开始,怎么也获取不到数据,想了许久,最后发现,是自己少定义了一个变量,也就是var变 ...

随机推荐

  1. PPT 商务报告:如何建立专属PPT素材库

    PPT 商务报告:如何建立专属PPT素材库 为什么建立素材库? 省事:直接套用 应对紧急环境:无网络情况下,无法搜索 提升设计思路:帮助提升思路 通用型素材库 企业型素材库 模板 灵感网站 使用场景 ...

  2. OpenFeign FormData

    服务端接口代码如下: /** * 上传数据+实体信息 */ @RequestMapping("/upload") public String doctorAnalysis(Http ...

  3. signed main 和 int main 的区别

    事实上只是因为有人直接 #define int long long 了...然后int main改成signed main就行了 #define int long long ... signed ma ...

  4. 技术分享 | 不同格式标准SBOM清单横评:SPDX、CDX和DSDX

    为了保证安全性.降低开发.采购及维护的相关成本,复杂动态的现代软件供应链对软件资产透明度提出了更高的要求.使用清晰的软件物料清单(SBOM)收集和共享信息,并在此基础上进行漏洞.许可证和授权管理等,可 ...

  5. 深度学习基础课: “判断性别”Demo需求分析和初步设计(下2)

    大家好~我开设了"深度学习基础班"的线上课程,带领同学从0开始学习全连接和卷积神经网络,进行数学推导,并且实现可以运行的Demo程序 线上课程资料: 本节课录像回放1 本节课录像回 ...

  6. v-html会导致xss攻击

  7. hdu 5234

    题意:求在不超过k的情况下,最多可以得到多少价值. 三维dp,结合01背包,第三维就是用来保存在不同的背包容量下能得到的最大价值,也就是第三维有很多状态. #include<iostream&g ...

  8. 03-Shell环境变量深入

    1. 自定义系统环境变量 1.1 全局配置文件/etc/profile应用场景 当前用户进入Shell环境初始化的时候会加载全局配置文件/etc/profile里面的环境变量, 供给所有Shell程序 ...

  9. Keep English Level-04

    firm -- 坚定的,坚固的;公司 share -- n 股份,份额 executive -- 执行官 There is no chance,no density,no fate,that can ...

  10. 21-CMOS门电路的逻辑式

    CMOS门电路的逻辑式 通过CMOS门电路,写出门电路的表达式. 方法 只看下方,因为电路上下是对称的: 先找L(输出)的非,找的输出到地的通路,以原变量进行书写.最后将表达式取非,即可得到L.这种方 ...