在斯坦福公开课《编程范式》中见到的几种特殊的无线循环,需要从内存模型、汇编的角度理解,蛮有意思的。
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,于是无限循环下去。