漏洞描述:
使用查看展开式
(macroexpand-1 '(do-primes-2 (p 0 (random 100)) (format t "~d~t" p)))
返回结果:
(DO ((P (NEXT-PRIME 0) (NEXT-PRIME (1+ P)))) ((> P (RANDOM 100))) (FORMAT T "~d~t" P))
当运行展开式时,random将在每次进行循环的终止测试时被求值一次,
这样循环就不会在p大于一个初始给定的随机数时终止
而是在循环刚好生成一个小于或等于当前p值的随机数时循环才停止
由于循环的整体次数是随机的
因此它将产生一个与random所返回的统一分布相当不同的分布形式
修复方法:
只需要在生成代码时对end求值一次,并将其值保存在一个稍后会用到的变量值中。
在do循环中,用一个初始形式但没有步长形式来定义的变量会不在迭代过程中改变其值
因此将end放到初始变量中
;;;修复end多次求值漏洞
(defmacro do-primes-3 ( (var start end) &body body)
`(do ((ending-value ,end)
(,var(next-prime ,start) (next-prime(1+ ,var))))
((> ,var ending-value))
,@body))
经过这一调整,end的随机值漏洞被修复,但同时又引进了两个漏洞。
本节先修复第一个漏洞,下一节再修复第二个漏洞。
因为在do循环中,变量的初始形式是以变量被定义的顺序来求值的
当宏展开被求值时,传递给end的表达式将在传递给start

本文详细介绍了LISP编程中在do-primes-2宏展开时遇到的问题,即随机end值导致的循环不终止以及调用顺序错误。漏洞表现为循环次数依赖于随机数生成,而非预期的条件。修复方案包括在循环开始前计算并保存end的随机值,以及调整宏展开时变量初始化的顺序,避免副作用形式的求值顺序错误。
最低0.47元/天 解锁文章
654

被折叠的 条评论
为什么被折叠?



