C 语言漏洞的深层根源:语义不变量

A theory for decades of C vulnerabilities

C 语言数十年的安全漏洞并非偶然,其根源在于语言类型系统无法强制约束“语义不变量”。变量 `length` 或指针 `p` 在类型上只是数字或地址,但程序逻辑却依赖它们代表特定的缓冲区大小或对象生命周期。当这些隐含的语义关系(如 `length` 不超过 `extent(p)`)未被语言强制,而仅靠程序员维护时,整数溢出、缓冲区溢出、越界访问和 Use-after-free 等看似不同的漏洞,实则是同一链条上语义断裂的不同表现。文章指出,真正的内存安全不应仅靠操作规范,而应成为语言本身的属性,让语义不变量在编译期或运行期得到保障。

漏洞的本质,是程序对现实的描述不再与现实本身相符。
  1. titzer

    > 初稿的很大一部分是在人工智能的协助下生成的。作者提供了核心概念和创作方向,并在书籍开发过程中广泛使用 AI 工具,对材料进行选择、重组、编辑、重写和润色。最终成书体现了作者的创作愿景和编辑决策。

    我很好奇,作者是如何说服 AI 忽略几十年来关于描述编程语言实现的大量既有工作,从而产出一部看似毫无先例的作品?

  2. hackthemack

    很多年前,当强类型成为互联网上被大肆推崇的编程信条之一时,我就有过类似的疑问。

    即使是动态类型编程语言,也会布局好语言包含哪些类型。但这通常只是基于多年历史形成的惯例,往往也是基于 C 语言。

    但如果你想要定义一个自定义类型来使用呢?比如你想创建一个名为 mysmallint 的类型,它是一个介于 1 到 1000 之间的整数。现在,你可以编写代码来实现这一点,但这与声明类型 int 并不是一回事。

    *除非你使用的是 Haskell、F# 或其他我不了解的语言。

    如果你想要定义一个自定义类型,规定该字符串仅包含 ASCII 字符呢?你无法轻易将其定义为一种类型并在代码中传递。你必须编写自定义代码并进行检查。

  3. jakeinspace

    不可能全都要。如果你希望对数据或状态进行运行时断言,那就要付出代价。没什么能阻止你写出这套逻辑,并对所有输入输出进行“语义不变性”的清洗。但如果你希望语言隐式地帮你做这件事,那就必然会有开销。在这种情况下,换一种系统编程语言吧,然后接受这种权衡。

同日更多故事

2026-08-20