作者:张富春(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. python指定大小文件生成

    使用特定大小的随机数生成,使用随机数生成器生成特定大小的字节,并将其写入文件中 import os def generate_file(file_path, file_size_bytes): wit ...

  2. BAPI_PO_CHANGE 采购订单修改服务

    修改服务页签里面的价格和数量,达到修改净价和条件里面金额的目的 数据可以通过采购订单查询ESLH和ESLL表获取 "------------------------------------- ...

  3. JSP | application 对象详解 & 网站计数器实现

    原作者为 RioTian@cnblogs, 本作品采用 CC 4.0 BY 进行许可,转载请注明出处. 本篇学习自:C语言中文网,部分内容转载仅供学习使用. \[QAQ \] JSP applicat ...

  4. POJ - 3180 The Cow Prom ( korasaju 算法模板)

    The Cow Prom POJ - 3180 题意: 奶牛圆舞:N头牛,M条有向绳子,能组成几个歌舞团(团内奶牛数 n >= 2)?要求顺时针逆时针都能带动舞团内所有牛. 分析: 所谓能带动, ...

  5. 【收藏】Stable Diffusion 制作光影文字效果

    大家对于最近 Stable Diffusion 不断出新的视觉"整活"印象都很深刻,很多人对最近比较流行的制作光影文字很感兴趣,制作光影文字可以作为进阶 Stable Diffus ...

  6. <vue初体验> 基础知识 1、vue的引入和使用体验

    系列导航 <vue初体验> 一. vue的引入和使用体验 <vue初体验> 二. vue的列表展示 <vue初体验> 三. vue的计数器 <vue初体验&g ...

  7. uni-app editor富文本编辑器

    https://blog.csdn.net/xudejun/article/details/91508189

  8. Vue项目中使用 tinymce 富文本编辑器的方法,附完整源码

    Vue项目中使用 tinymce 富文本编辑器的方法,附完整源码 https://blog.csdn.net/snsHL9db69ccu1aIKl9r/article/details/11432414 ...

  9. IDE暗黑主题推荐-Dracula

    作为程序员,我们一天中会花费大量时间在编码和阅读代码上.优秀的代码编辑器主题可以减轻眼睛的疲劳,提高工作效率.本文向大家推荐一款非常流行的 JetBrains IDE 主题插件 - Dracula.它 ...

  10. lucene.net全文检索(一)相关概念及示例

    相关概念 站内搜索 站内搜索通俗来讲是一个网站或商城的"大门口",一般在形式上包括两个要件:搜索入口和搜索结果页面,但在其后台架构上是比较复杂的,其核心要件包括:中文分词技术.页面 ...