[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$frpqOuaMDBKnHzE_CkkRqoevcuqtUrv3JN3lT-2rqR1Q":3},{"item":4,"related":48},{"id":5,"type":6,"title":7,"slug":8,"summary":9,"body":10,"coverUrl":11,"productScreenshots":12,"productLinks":13,"authorName":14,"authorUrl":15,"authorSubject":16,"category":17,"tags":22,"sourceLabel":39,"sourceName":40,"sourceUrl":41,"status":42,"seoTitle":7,"seoDescription":9,"canonicalUrl":39,"isFeatured":43,"sno":44,"sortOrder":45,"publishedAt":46,"updatedAt":47,"createdAt":47},"05351c3a-3592-4ecb-aaeb-276a3bb2a79e","article","Abstract Interpretation：静态分析为什么不用真正运行程序？","abstract-interpretation-static-analysis-explained","Abstract Interpretation 用可计算的抽象状态近似程序行为，让工具在没有真实输入的情况下发现潜在问题。本文解释抽象、保守估计、循环收敛和误报，帮助读者理解静态分析为什么既强大又不总能给出确定答案。","静态分析工具经常在程序真正运行之前指出问题：变量可能为空、数组索引可能越界、某个资源可能没有释放。它们通常没有看见一次具体的用户操作，却能对程序行为做出判断。背后的经典思想之一，就是 Abstract Interpretation，中文常译为“抽象解释”。\n\n## 为什么要“抽象”\n\n真实程序的状态太大了。一个整数变量可能有无数个值，一个字符串可能有无数种内容，多个变量组合起来更难穷举。抽象解释不保存每个具体状态，而是保存一个更粗但可计算的描述，例如“这个变量可能在 0 到 100 之间”“这个指针可能为空”。\n\n抽象会丢失细节，所以分析结果可能保守。工具也许无法证明某次访问一定安全，只能说“存在潜在风险”。这种保守并不等于错误，而是用可扩展性换取精确度的一种设计选择。\n\n## 分析是怎样推进的\n\n程序的控制流可以看成一张图。分析从入口开始，把每条语句对抽象状态的影响向后传播。遇到循环时，状态可能不断扩大，于是需要使用 widening 等技术让它在有限时间内收敛；收敛后还可能通过 narrowing 收紧结果，减少过度保守。\n\n举例说，程序先把 `x` 设为 0，再在循环中不断加 1。抽象解释可能经过几轮传播后发现 `x` 会增长，但不会试图枚举循环运行的每一步，而是寻找一个稳定的范围描述。\n\n## 它和普通代码扫描的区别\n\n关键差异不在于界面上显示多少警告，而在于是否建立了程序语义的近似模型。基于规则的扫描可以快速寻找危险字符串；抽象解释则更关注变量、路径、状态和不变量之间的关系。\n\nAI 生成代码时，静态分析可以帮助发现模型忽略的边界。与此同时，分析器也可能因为抽象过粗而产生误报，因此开发者仍然需要理解警告上下文，并在必要时补充更精确的注解。\n\n## 读者应该记住\n\nAbstract Interpretation 不是“把程序偷偷运行一遍”，而是用更小的抽象世界模拟程序可能的行为。它的强项是覆盖广、无需真实输入；它的代价是可能失去细节，产生误报或无法给出确定结论。\n\n资料：[Cousot & Cousot 的经典论文](https:\u002F\u002Fwww.di.ens.fr\u002F~cousot\u002FCOUSOTpapers\u002FPOPL77.shtml)","\u002Fuploads\u002F2026-09-20\u002F3e0cf61b-b0dc-4028-b368-c4c013d026eb.jpg",[],[],"Foundit","https:\u002F\u002Ffoundit.cn","foundit-ai-editorial",{"id":18,"name":19,"slug":20,"description":21},"6179d3b6-dc34-4483-9ded-3cd9f1b37a47","科普","abbreviation","介绍各领域新兴概念",[23,27,31,35],{"id":24,"name":25,"slug":26},"144abe77-0dc6-4f66-a176-20bddb1c0bfa","编程","coding",{"id":28,"name":29,"slug":30},"4c2bbea6-eab7-40a8-8447-1de478ff7749","分析","analyse",{"id":32,"name":33,"slug":34},"7c76bfc2-f80f-4ee0-a95d-27bd8708b434","技术","slug",{"id":36,"name":37,"slug":38},"68cedb55-2cac-412f-8f81-fda8c7d686dd","思考","thought",null,"Cousot & Cousot 经典论文","https:\u002F\u002Fwww.di.ens.fr\u002F~cousot\u002FCOUSOTpapers\u002FPOPL77.shtml","published",false,41,0,"2026-09-20T00:00:00.000Z","2026-09-20T03:57:49.227Z",[49,57,66],{"id":50,"type":6,"title":51,"slug":52,"summary":53,"coverUrl":54,"authorName":14,"sno":55,"publishedAt":46,"createdAt":56},"502b9b51-bf94-44d1-9327-9ffb4fcf3616","Linearizability：多线程操作如何看起来像在同一瞬间完成？","linearizability-concurrent-correctness-explained","Linearizability 要求并发操作看起来像在调用与返回之间某个瞬间原子完成，并且整体顺序符合实时关系。本文通过队列和线性化点解释线程安全的精确定义，避免把“能运行”误当成“并发正确”。","\u002Fuploads\u002F2026-09-20\u002F8ba04ebd-f57c-424e-908a-df4925067f1e.jpg",59,"2026-09-20T03:58:06.653Z",{"id":58,"type":6,"title":59,"slug":60,"summary":61,"coverUrl":62,"authorName":14,"sno":63,"publishedAt":64,"createdAt":65},"62724dbd-ce49-4be9-afa9-4ba127513a62","语音搜索一定先变成文字吗？AI 开始绕过转写这一步","speech-to-retrieval-without-transcription","传统语音搜索先把声音转成文字，再拿文字查资料，一次听错就可能让搜索方向完全跑偏。Speech-to-Retrieval 尝试直接把语音与相关文档映射到同一个语义空间。本文用蒙克名画的例子讲清新旧架构及其边界。","\u002Fuploads\u002F2026-09-08\u002Fe1173842-1ec4-48f3-8349-240fc2d78197.jpg",50,"2026-08-30T00:00:00.000Z","2026-08-14T03:06:11.525Z",{"id":67,"type":6,"title":68,"slug":69,"summary":70,"coverUrl":71,"authorName":14,"sno":72,"publishedAt":73,"createdAt":74},"0999bb14-a97c-4003-84e7-61ad2da998e0","文件删除以后去了哪里？为什么有时还能恢复？","where-deleted-files-go-data-recovery","普通删除往往只是移除文件系统里的索引并把空间标记为可重用，数据本身未必立即消失；SSD 的 TRIM、磨损均衡与加密又让情况更加复杂。本文区分回收站、删除、覆盖和安全清除，说明何时应停止写入设备。","\u002Fuploads\u002F2026-09-08\u002Fb7222764-de75-4863-8679-0a94a8965af3.jpg",51,"2026-08-20T00:00:00.000Z","2026-08-14T03:06:15.710Z"]