逻辑问题 导致系统漏洞
凌晨两点,逻辑漏洞我盯着屏幕上那条报错日志,问题咖啡杯沿沾着干涸的系统指纹。系统又崩了,逻辑漏洞第三次。问题不是系统硬件故障,不是逻辑漏洞网络延迟,是问题逻辑——代码里那个“如果A则B,否则C”的系统判断,在边界条件下走了第三条路。逻辑漏洞
写这段程序的问题人是个聪明人,他考虑到了用户输入为空、系统超长、逻辑漏洞特殊字符,问题甚至考虑到了并发冲突。系统但他漏掉了一种情况:当用户输入的字符串恰好是数据库里某条记录的ID,而这条记录刚好被软删除时,系统会先查缓存,再查主库,最后落到一个“不存在”的返回值上。他写的逻辑是“如果查不到,就新建”,可新建的流程里又调用了同一个查询接口——死循环就这样形成了。
这种问题最坑的地方在于,它平时不发作。测试数据干净,生产环境的数据脏。真实用户不会按测试用例操作,他们会复制粘贴一段带换行符的文本,会在两个页面之间来回切换,会在提交前把浏览器后退键按了十几次。每个动作单独看都符合逻辑,组合起来就撞上了那个没人预料的缝隙。
我认识一个运维老哥,他处理过最诡异的bug:某电商平台在每年双十一凌晨的某个特定时段,会有千分之一的订单金额多算一分钱。排查了三天,最后发现是促销规则里的“满减”和“折扣”叠加时,浮点数精度在小数点后两位舍入的次序出了问题。业务逻辑上没错,数学上也没错,但计算机的二进制浮点表示法不这么想。他后来说了句话我记到现在:“逻辑对错不是看代码本身,是看它跑在什么环境里。”
回到那个死循环。修复方案很简单,加个标志位判断“是否正在新建流程中”。但真正让我难受的是,写出这个漏洞的同事是个逻辑思维极强的人。他能在白板上画半小时流程图,把每个分支都讲得头头是道。可现实世界不是流程图。现实有状态,有时间,有并发,有脏数据。逻辑越严密,越容易假设环境是干净的——这本身就是最大的逻辑漏洞。
现在很多系统架构都在强调“防御性编程”,本质上是承认逻辑不完备。你没法预判所有情况,那就加超时、加重试、加降级、加兜底。但兜底本身也需要逻辑,而那个逻辑又可能有漏洞。这是个无限套娃的游戏。我见过最务实的做法,是开发团队专门养一个“破坏者”,每天的工作就是故意用反逻辑的方式操作系统——乱点按钮、中途断网、快速切换账号。大部分时候系统扛住了,偶尔崩一次,大家反而松口气:又补上一个坑。
凌晨三点半,我改完代码,加了那个标志位,顺手在注释里写了句“别删,删了会死”。我知道这语气不像正规技术文档,但管用。下次那个聪明同事再review代码时,看到这行字,至少会多停两秒。逻辑问题永远存在,但只要人还在警惕它,系统就还能跑。
