欢迎光临散文网 会员登陆 & 注册

记一个十分诡异的bug:结构体的内容会莫名其妙的变化。

2023-06-12 11:19 作者:豆芽Doxel  | 我要投稿

本文节选自我的实验报告。
北航的操作系统课程会在学期末布置若干个"挑战性任务",任务要求是在本学期完成的系统内核中增添新的功能。我选择的挑战性任务是实现进程间通信的信号机制,下文记录了我在传输信号结构体时遇到的一个bug。解决这个bug的过程加深了我对系统编程的理解,特此记录。

这个诡异的现象如下图所示。其中s是指向struct signal结构体的指针。

满脸问号


明明没有修改s->signum的值,为什么输出结果会发生变化呢?难道是sigx自减时修改了它的值?还是说printk修改了它的值?这都不可能啊。

单看这一段代码,我实在是摸不着头脑。



抓耳挠腮了很久,我终于找到了问题所在,在新建信号结构体时,我是在一个函数内部新建了一个struct signal结构体,再将链表里的指针指向这个结构体。代码如下:

 int sys_sendsig(u_int envid, int sig) {
  ...
  struct signal s = {.signum = sig};
  TAILQ_INSERT_HEAD(&e->sig_pending, &s, sig_link);
  ...
 }
 

我在用java写oo作业时,经常会写出这样的业务逻辑,并且不会出现bug。这种写法很直观,很容易理解,就是新建一个东西再放到链表里嘛。

但是在系统内核里就不能这么写,这么写就会出bug。

问题就出在"在一个函数内部新建结构体",这只是在栈上申请了一个局部变量,当这段空间释放后被重新使用时,这段空间原有的内容就会被覆盖。

为了解决这个问题,我联想到了Env结构体的组织方式:先使用全局变量申请固定的空间,这样结构体的内容就不会被更改了。每次需要申请信号结构体时,只需要取出一份来用就可以了。代码如下:

 // lab4-challenge
 struct signal sigs[SIG_BUFFER] __attribute__((aligned(BY2PG)));

解决这个bug的经历,是我这次挑战性任务收获最大的部分。

我深刻体会到,编写系统内核对内存的操作要极其敏感,而且需要熟练掌握底层知识,让自己的思维更加缜密。


记一个十分诡异的bug:结构体的内容会莫名其妙的变化。的评论 (共 条)

分享到微博请遵守国家法律