作者:张富春(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. css过去及未来展望—分析css演进及排版布局的考量

    读初二的时候,学校有了计算机,也简单地介绍了下网页,不过那是的html 都是table,也没有去细看.到了高中,qq空间有个html模式,为了让文章好看点.也浅尝辄止地学了下css css简介 在HT ...

  2. zsh踩坑记录

    1. zsh: no matches found: uvicorn[standard] 方法一 # 在~/.zshrc中添加下面这句话 setopt no_nomatch # 然后source ~/. ...

  3. Problem 1342B - Binary Period (思维)

    AC代码: #include<bits/stdc++.h> using namespace std; int main() { //freopen("in.txt", ...

  4. 无需代码绘制人工神经网络ANN模型结构图的方法

      本文介绍几种基于在线网页或软件的.不用代码的神经网络模型结构可视化绘图方法.   之前向大家介绍了一种基于Python第三方ann_visualizer模块的神经网络结构可视化方法,大家可以直接点 ...

  5. 二、Mycat安装

    系列导航 一.Mycat实战---为什么要用mycat 二.Mycat安装 三.mycat实验数据 四.mycat垂直分库 五.mycat水平分库 六.mycat全局自增 七.mycat-ER分片 万 ...

  6. map三层循环遍历,操作数据

    let tempArr = this.oldCityList.map(item => { return { value: item.code, text: item.name, type: it ...

  7. ttf转eot

    Webfont Generator https://www.fontsquirrel.com/tools/webfont-generator 使用@font-face显示web自定义字体,字体获取工具 ...

  8. 05_二叉树的层次遍历II

    二叉树的层序遍历 II 给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 . (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历) 示例 1: 输入:root = [3,9,20 ...

  9. linux 通过docker安装 elasticsearch-head

    本文为博主原创,未经允许不得转载: 1. 使用docker安装 elasticsearch-head #拉取镜像 docker pull mobz/elasticsearch-head:5 #创建容器 ...

  10. MCU芯片架构设计

    目录 1.应用场景 主要是I2C\UART\SPI协议 2.Cortex-M3 MCU成本与工艺选型 按照晶圆进行收费,28nm,12寸晶圆,400万美金 晶圆是圆形的,die是方形的,会存在浪费 p ...