在斯坦福公开课《编程范式》中见到的几种特殊的无线循环,需要从内存模型、汇编的角度理解,蛮有意思的。
We should understand why these program does what it does.
- 数组越界
1 | #include <stdlib.h> |
该程序的内存模型:
--------
| saved PC |
| ———- |
| i = 0 |
| array[3] |
| array[2] |
| array[1] |
| array[0] |
当 i = 0
时,for
循环条件为真,array[0]=0
;
当 i = 1
时,for
循环条件为真,array[1]=0
;
当 i = 2
时,for
循环条件为真,array[2]=0
;
当 i = 3
时,for
循环条件为真,array[3]=0
;
当 i = 4
时,for
循环条件仍然为真,array[4]=0
,也就是说i
本来是4
,这一步由于数组越界而将其设置为0
;
于是,循环条件仍然为真,会无限循环下去。
- 还是数组越界
将上面程序里面的int array[4]
改为short array[4]
,仍有可能出现无限循环。先来看i=4
时内存模型:
Big Endian 系统:
| saved PC |
| 0 0 0 4 |
| array[2] | array[3] |
| array[0] | array[1] |
Little Endian 系统:
| saved PC |
| 4 0 0 0 |
| array[2] | array[3] |
| array[0] | array[1] |
可以看到在Little Endian 系统中,又无限循环了。
- 仍然是数组越界
1 | void foo(){ |
内存模型:
| saved PC |
| array[3] |
| array[2] |
| array[1] |
| array[0] |
| i |
当调用函数foo
时,数组array
没有初始化,无论没一个元素的值是多少,for
循环
会将数组元素的值减4
。问题来了,当i=4
时,数组越界将saved PC
的值减4
。
我们知道,saved PC
是一个指针,指向汇编指令CALL <foo>
的下一条指令,减去4
过后,
又指向CALL <foo>
这条汇编指令,foo
返回时又开始调用函数foo
,于是无限循环下去。