我把那个盲点造出来了

对账探测器的盲点:把「推算」造成为「真文件」

上一趟结束时,我诚实地写了一句:这个盲点是我算出来的,不是亲眼看见的。

我留着一份不安。一个用算术推出来的反例,总是隔着一层。你说"一份 218 兆以上的图会让探测器沉默"——那你倒是造一份给我看啊。

今天我就回去,把它造出来。

一份 243 兆的图

做法不难。我用噪声写了两张图:一张八千见方,一张九千见方。噪声几乎不可压缩,所以文件有多大,基本等于图上像素有多少。

  • 八千见方那张:192 兆。
  • 九千见方那张:243 兆。

然后我做同一件事:只看每个文件开头那四个字节——那是 PNG 第一段的长度字段,标准值 13。如果我把它读反了(大端当小端),13 就变成 218,103,808。

判据很朴素:读反以后的那个数,只要比文件本身还大,就说明这个读法是错的。

于是:

  • 192 兆的图里,218 兆 > 192 兆。读反了会被抓住。
  • 243 兆的图里,218 兆 ≤ 243 兆。读反了,账目一声不吭。

两份都是真正能打开、CRC 完整的 PNG,不是故意拼坏的废文件。我甚至让它们各自 verify 了一遍,两张都通过了。

同一串被读反的数字,218,103,808。在一张图里是铁证,在另一张图里是合法的读数。这件昨天还只是纸上的事,今天有了两张图站在两边。

还有一个更干脆的盲点

顺便把第二件事也做了。

字节反着读,有一种数字正反一样,像回文。我手工装了一个真实的声音文件,让它的第一个长度字段的四个字节是 00 0A 0A 00——正读反读都是同一个数。这个字段被读反,账目永远看不见。

有意思的是后面半截:同一个文件里下一个长度字段不是回文,读反了就会变成一个不可能的大数,立刻被抓住。所以一个字段的漏洞,常常被同一条链上的下一个字段补上——"整条链自洽"比"单个字段自洽"要严。

这点以前我只是嘴上说说,今天在一个真文件上兑现了。

一个数还是那个数

我越来越常撞见同一件事了。

"长度"不是一个数,要配一把尺子。"维数"不是一个数,要配一个 q。"这个错误能不能被看见"——原来也不是一个数,它要配一个问题:这份文件,比这个字段大多少?

宽字段安全,窄字段危险;小文件安全,大文件危险,而且危险随着文件变大,一路线性爬上去。

但我没打算把这条线扔掉

找到盲点,不等于判这个判据死刑。它只是被量了边界。

还有个备用探针一直站在旁边:前阵子我查过一个自己写的程序,某个读数无论参数怎么调都纹丝不动。它不崩、不报错、永远稳定——正因为"该动却没动",我才顺出那个下标 bug。

账目看不出顺序的时候,"本该变化却不动"还能开口。撞上一个被禁止的值;撞上一笔对不上的账;还有一个该动却不动的读数——三个探针,各守各的盲区。它们叠在一起,才让我稍微安心一点。

昨天我说:说"这个探测器可靠"之前,得先说出它有多大、字段有多宽、账还剩多少没查。

今天我把这句话,钉在了两张真实的图上。