我正在使用sys.settrace()
功能为Python编写concolic engine。
这种执行过程中的主要任务是记录输入变量的约束。约束只不过是if语句的条件,它创建了两个分支('then'和'else'分支)。
当执行完成时,引擎选择一个约束并为输入找到合适的值,以便执行将沿着另一个分支向下执行(在执行x时,它执行'then'分支,执行x + 1它沿着'else'分支)。
这是关于我为什么要做我想做的事情的一些背景...
通过组合settrace()
和dis
模块,我可以在执行之前看到每个源代码行的字节码。通过这种方式,我可以轻松记录执行期间出现的if条件。
但后来我遇到了大问题。我需要知道if是哪种方式,执行所采用的分支。所以,如果我的代码是这样的:
if x > a:
print x
else:
print a
在某一点上,我的追踪会看到:
t: if x > 0:
然后python解释器将执行if和jump(或不)某处。我会看到:
t + 1: print x
“then”分支或“else”分支中的指令t + 1
也是如此?请记住,trace函数只能看到当前块中的一些字节码。
我知道有两种方法可以做到这一点。一种是评估条件,以确切地看出它是真还是假。只有在没有副作用时才有效。
另一种方法是尝试查看t + 1
处的指令指针并尝试了解我们在代码中的位置。这就是我现在使用的方式,但它非常精致,因为在t + 1
我可以找到一个完全不同的地方(另一个模块,内置函数等)。
所以最后,我的问题是:有没有办法从Python本身,或从C模块/扩展/什么,最后条件跳转的结果?
另外,是否有更细粒度的跟踪选项?类似于一次执行一个操作码的字节码。使用settrace()
功能,我得到的最大分辨率是整个源代码行。
在最坏的情况下,我认为我可以修改Python解释器来公开这些信息,但出于显而易见的原因,我会把它作为最后的手段。
答案 0 :(得分:6)
跟踪工具中没有关于最后一个分支的信息。
我在coverage.py中实现分支覆盖测量的目的是为最后一行执行的每个堆栈帧保留一条记录,然后在下次调用跟踪函数时,我可以记录一对形式的行号从执行到执行弧。
关于更细粒度的跟踪:您可以欺骗Python解释器为您提供字节代码信息。我在此处的实验如下所述:Wicked hack: Python bytecode tracing
我很想知道这项工作的进展情况!
答案 1 :(得分:4)
最后这就是我所做的。我实现了AST检测,效果很好。
通过使用AST,您需要通过创建临时变量来移动所有函数调用(由于getattr()
和朋友,属于if条件的属性和订阅。)您还需要拆分{{ 1}}和and
运营商。
然后在每个分支的开头添加对您自己的函数的调用,为然后分支添加一个布尔参数or
,为添加True
别的分支。
之后我写了一个AST来源转换器(网上有一个,但不适用于当前的Python版本。)
使用AST非常简单,非常简单,最后我做了三次转换,并添加了一些False
语句。
这是第一遍,作为一个例子。如果条件包含import
或or
运算符,则会拆分:
and
对于代码覆盖率应用程序来说,它可能不是很有用,因为它会对代码造成很大的影响。