一个在 Go 运行时中修复了三年的 bug

全文整理自 golang issue#3250

2012年3月9日:发现

一名开发者在使用 cgo 调用 gtk 时,程序持续报 segment fault,其程序非常简洁:

package main

/*                                                                              
#include <gtk/gtk.h>                                                            
                                                                                
#cgo pkg-config: gtk+-3.0                                                       
*/
import "C"

func main() {
        C.gtk_init(nil, nil)
        C.gtk_file_chooser_button_new(nil, 0)
}

对应程序的 C 版本无此问题:

#include <gtk/gtk.h>

int main(int argc, char **argv)
{
        gtk_init(0, 0);
        gtk_file_chooser_button_new(0, 0);
}

在经过一番简单的背景调查后,rsc(Russ Cox,Go 的核心开发人员)很快就想到了触发场景:通过 cgo 调用的 C 函数创建了私有线程,这些线程继承了 Go 的信号处理函数,而 Go 的信号处理函数并不能与非 Go 线程良好合作。

2012年3月13日:增加诊断日志

rsc 提交了一个简单的 fix,在触发此 bug 时,打印出非 Go 线程接收到具体信号,并认为目前没有能力在 Go 1.0 发布前 fix 此 bug。自此,该 bug 石沉大海。

2013年6月13日:重新提上日程

15个月后,一位名叫 joshrickmar 的开发者遇到了相同问题:使用 cgo 调用 gtk,程序意外退出。

在有了 rsc 的诊断日志后,该开发者明确了能够导致程序崩溃的信号集,并提交了一个 适用于 OpenBSD 平台的 fix,其修复方案为:直接忽略导致程序崩溃的信号集。

2013年7月12日:初步修复

minux(Go 的开发人员)进一步完善 joshrickmar 的修复方案,对于非 Go 线程中 Go 运行时(os/signal.Notify)不关心的信号,直接忽略。并将修复方案适配到了所有已支持平台,完成了对该 bug 的初步修复。

隐患

忽略信号确实解决了使用 cgo 调用 C 函数导致程序崩溃的问题,但于此同时,也带来了隐患。举个例子,程序在非 Go 线程里运行的代码存在 bug,比如写乱内存,正常情况下,程序会因为收到 segment fault 而退出。而直接忽略 SIGSEGV 会导致僵尸线程,实际上,线程已经 crash,却因为 SIGSEGV 被吞掉,不被外界所知。这种 bug 极其隐蔽,会严重推迟问题的暴露时间,造成不可估量的影响,而且还给问题的定位平添麻烦。

2015年7月22日:最终修复

2年后,ianlancetaylor(Go 的开发人员)最终修复了该 bug,其修复方案简单直觉:对于非 Go 线程中 Go 运行时不关心的信号,将信号处理权力归还给用户。

至此,完美地解决了该 bug。

Timeline

2012年3月09日 发现
2012年3月13日 增加诊断日志

2012年3月28日 Go 1.0 发布
2013年5月13日 Go 1.1 发布

2013年6月13日 重新提上日程
2013年7月12日 初步修复

2013年12月01日 Go 1.2 发布
2014年06月18日 Go 1.3 发布
2014年12月10日 Go 1.4 发布

2015年7月22日 最终修复

2015年8月19日 Go 1.5 发布
2016年2月17日 Go 1.6 发布
2016年8月15日 Go 1.7 发布

测试程序

我写了一份测试程序用以验证该 bug 在不同 Go 版本中的表现,我测试了 Go 1.4 和 1.7 两个版本,结论如下:

  1. 对于 Go thread 中触发的 segfault,无论哪个版本都会导致程序 crash。
  2. 对于 C thread 中触发的 segfault
    在 1.4 中,segfault 信号会被悄无声息的吞掉,出错线程僵死,进程不退出
    在 1.7 中,segfault 会导致进程 crash

与此同时,程序中也给出了在低版本 Go 中的修复方案:既然 Go 运行时中的信号处理函数会吞掉其不关注的信号,那么在 C 线程启动后,重置相应信号的处理函数即可。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,062评论 25 707
  • 阳光的心态,总是能带来阳光般的好心情。迎着阳光成长,任何负面的情绪都会被阳光蒸发掉。向着太阳成长,无论在哪里都...
    秋日雏菊阅读 379评论 0 1
  • 随着科学的进步,生活水平的提高,养生,已不再只是老年人关注的话题。现在越来越多的年轻人也十分注重养生的,但对于“养...
    ssggou阅读 308评论 0 0
  • input和textarea区别: input是当行文本框,其type值必须是text,初始值是用value或者p...
    石子1110阅读 231评论 0 0
  • 从初中开始,就保持着一个习惯:指甲稍微长一点,就会用指甲钳把指甲剪到接近指甲与肉的接缝。 今天又拿起指甲钳要剪指甲...
    水上车痕阅读 235评论 0 0