在许多情况下,我们编译 C 程序并执行二进制文件时,无需担心原始源文件是否发生变化。不过,我很好奇:
正在运行的 C 程序是否可以检测其自身的.c
源文件在编译后是否被修改?
需要考虑的一些限制:
- 程序应该检查其源文件中的修改,而不仅仅是二进制文件(
a.out
) - 它不应该依赖于外部工具,例如
md5sum
或stat
通过system()
调用。 - 该解决方案应适用于常见的操作系统(Linux/Windows)
- 它应该纯粹用 C 来完成,使用标准或广泛可用的系统库。
这是否需要在运行时读取源文件并比较时间戳或哈希值,或者是否有更优雅的方法来实现这一点?
确定哪些文件是“其源代码”存在重大问题。机器上可能有数百万份副本,也可能没有。也许有副本,但没有一份用于编译程序。该程序可能是在另一台机器上编译的。
但除此之外,当然可以。查看文件是否已更改只需读取它并将其与先前存储的副本进行检查即可。在 C 中,读取文件和复制内存块很简单。
为了节省空间,你可以在二进制文件中保存源文件的加密哈希值,而不是保存源文件本身。虽然比较复杂,但仍然很容易做到。
为了节省时间,您还可以使用与文件大小和文件修改时间相关的启发式方法来跳过逐字节检查文件。不过,这会降低可靠性。使用
stat
库调用(而不是外部工具)可以轻松检查文件大小和文件修改时间。如果不假设这些文件是什么,那就不行。编译后的二进制文件和构建二进制文件的 C 源文件(可能有许多文件对单个程序有贡献)之间没有持久的联系。在程序尝试进行这样的检查之前,它需要以某种方式确定需要检查哪些文件。
而且不可靠。该程序最多可以检查所选的用于测试的源文件是否具有与其构建源相同的属性和内容,但它无法排除某些文件在构建和运行之间被更改然后又改回来的可能性。
即使可以确定这些信息,也没有什么用,因为这些信息很快就会过时。程序可能能够确定它在运行时观察到的某些文件是否与它所基于的文件相匹配,但它只知道它们在测试时是否匹配。不能安全地假设它们在测试后的任何时间内继续匹配,也不能假设测试结果在最初确定时是正确的。例如,也许文件在测试的同时被修改,这样测试完成时读取的状态已经不同了。
确定了需要测试的文件之后——这绝非易事——接下来的问题就是您真正想要了解什么信息。
您可以将当前时间戳与二进制文件中记录的时间戳进行测试,但这只能告诉您时间戳是否匹配。这可以作为您的标准,但它非常薄弱,因为时间戳很容易被操纵。另一方面,它快速而简单,因为它只需要读取文件的元数据,而不是其内容。
您可以单独或集体计算文件的哈希值或校验和,并将其与二进制文件中存储的预期值进行比较。这需要读取每个文件的每个字节,并且它会提供概率结果,而不是确定的结果。但是,它只需要将哈希值或校验和存储在可执行文件中。(或存储在外部文件中,但这也代表了另一种可能使测试混乱的方式。)
您可以读取每个文件的每个字节,并与存储在某处的副本进行比较。C 本身不提供将这个“某处”置于二进制文件内部的方法,但有办法让链接器执行此类操作。如果存储是外部的,那么这种方法的效果只与程序测试的源副本一样好。如果是内部的,那么副本将占用二进制文件中的相当大空间。
我不确定您能想到哪种“更优雅”的解决方案。如果您想了解某些文件在运行时的状态,那么您必须在运行时检查这些文件。