您似乎正在寻找某种价值范围分析,并检测该范围何时会超过设定的界限。这是一件表面上看起来很简单,但实际上很难的事情。会有很多误报,即使不计算实现中的错误。
暂时忽略细节,您将一对[lower bound, upper bound] 与每个变量相关联,并进行一些数学运算以找出每个运算符的新界限。例如,如果代码添加了两个变量,则在您的分析中,您将上限加在一起形成新的上限,并将下限加在一起以获得新的下限。
但当然没那么简单。首先,如果有非直线代码怎么办? if 还不错,您可以只评估双方,然后取其后的范围的并集(这可能会丢失信息!如果两个范围之间有间隙,它们的并集将跨越间隙)。循环需要技巧,一个简单的实现可能会在循环上运行数十亿次分析迭代,甚至根本不会终止。即使您使用没有无限上升链的抽象域,您仍然会遇到麻烦。解决此问题的关键字是“加宽运算符”和(可选,但可能是个好主意)“收窄运算符”。
比这更糟糕,因为什么是变量?您的标量类型的常规局部变量永远不会被占用,这还不错。但是数组呢?现在您甚至不确定哪个条目受到影响——索引本身可能是一个范围!然后是混叠。这远非一个已解决的问题,并导致许多现实世界的工具做出非常悲观的假设。
还有,函数调用。您将从某些上下文中调用函数,希望是已知的(如果不是,那么很简单:您什么都不知道)。这很困难,不仅突然间要同时跟踪更多状态,还可能有几个地方可以调用函数,包括自身。对此的通常反应是在其参数之一的范围已扩展时重新评估该函数,如果不仔细执行,这可能需要数十亿步。还有一些算法可以针对不同的上下文对函数进行不同的分析,这样可以提供更准确的结果,但很容易花费大量时间来分析差异不大的上下文。
无论如何,如果您已经做到了这一点,您可以阅读Accurate Static Branch Prediction by Value Range Propagation 和相关论文,以了解如何实际执行此操作。
这还不是全部。仅考虑单个变量的范围而不关心(关键字:非关系抽象域)它们之间的关系,这对非常简单(对于人类读者)的事情不利,例如减去两个值总是接近的变量,为此它将产生一个很大的范围,假设它们可能在它们的界限允许的范围内相距很远。即使是一些琐碎的事情,例如
; assume x in [0 .. 10]
int y = x + 2;
int diff = y - x;
对于人类读者来说,diff = 2 很明显。在到目前为止描述的分析中,结论将是y in [2 .. 12] 和diff in [-8, 12]。现在假设代码继续
int foo = diff + 2;
int bar = foo - diff;
现在我们得到foo in [-6, 14] 和bar in [-18, 22],即使bar 显然又是2,范围又翻了一番。现在这是一个简单的示例,您可以编造一些临时黑客来检测它,但这是一个更普遍的问题。这种影响往往会迅速扩大变量范围并产生大量不必要的警告。部分解决方案是将范围分配给变量之间的差异,然后您会得到所谓的差异绑定矩阵(不出所料,这是 relational 抽象域的示例)。对于过程间分析,它们可能会变得又大又慢,或者如果您也想向它们抛出非标量变量,那么算法就会开始变得更加复杂。而且它们只能让你到目前为止 - 如果你在混合中加入乘法(包括x + x 和变体),事情仍然会很快变坏。
因此,您可以在混合中添加可以处理乘以常数的其他内容,例如 Abstract Domains of Affine Relations⋆ - 这与范围非常不同,并且它本身不会告诉您有关变量范围的太多信息,但您可以使用它来获得更准确的范围。
故事并没有就此结束,但这个答案越来越长。我希望这不会阻止您研究这个主题,这个主题非常适合从简单的开始,并为您的分析工具添加越来越多有趣的东西。