【形式化方法】Part A: Concrete execution(具体执行)

在这节课中,我们讨论了定义程序语义的一种特定风格:操作语义,即程序在某些虚拟机上执行。我们还讨论了符号执行,它类似于操作语义,只是程序是在一个符号虚拟机上执行的,所有的程序路径都是以系统的方式探索的。最后,我们讨论了concolic的执行,即程序的具体执行和符号执行。

在这个任务中,我们将构建几个执行器:具体执行器、符号执行器和concolic执行器。具体来说,这个作业分为四个部分,每个部分都包含一些教程和问题。第一部分是关于具体执行的,您将根据我们在类中讨论的大步骤操作语义实现一个执行器;第二部分是符号执行,第三部分是concolic执行,它将符号执行和具体执行相结合;最后,也就是最后一部分,我们将通过将这种技术应用于一个很容易理解的安全问题:SQL注入,来获得一些符号执行应用程序的经验。有些问题被标记为练习,你应该解决。还有一些问题被标记为挑战,它们是可选的。首先下载这个代码模板。

Part A: Concrete execution(具体执行)

具体执行的思想很简单:我们构建一个虚拟机来执行程序。VM的执行规则遵循操作语义规则(大步骤或小步骤,取决于您选择的样式)。在很多情况下,这样的执行引擎通常被称为解释器,因为我们直接解释代码,而不是将它们编译为本地代码。

在本部分中,我们将为MiniPy语言构建一个具体的执行器(解释器)。

MiniPy的抽象语法:

其中非终结符F表示函数,(x1, ..., xn)表示函数的参数,S表示函数中的语句,E表示函数的返回表达式;非终结符S代表一个语句;非终结符E代表一个表达式;非终结符B代表一个二进制操作符。

您将构建的具体执行程序(解释器)将直接执行MiniPy的源代码。为此,您将首先构建数据结构来表示MiniPy的语法,这种数据结构称为抽象语法树(AST),正如我们在前面的作业中多次看到的,针对各种语言。

练习1:阅读mini_py中的代码。它包含我们为您定义的AST数据结构。为了保持简单(但不是更简单),我们修改了MiniPy语法,最大的变化是删除了函数调用语句f(E1,…,En)。你还会发现函数类中的魔法方法__str__()没有实现。你在这个练习中的任务就是完成它。完成代码之后,不要忘记运行测试用例以获得所需的代码打印结果。

# This bunch of code declare the syntax for the language MiniPy:
'''
B ::= + | - | * | / | == | != | > | < | >= | <=
E ::= n | x | E B E
S ::= pass
    | x = E
    | seq(S, S)
    | f(E1, ..., En)
    | if(E, S, S)
    | while(E, S)
F ::= f((x1, ..., xn), S, E)
'''


##################################
# bops
class Bop(Enum):
    ADD = "+"
    MIN = "-"
    MUL = "*"
    DIV = "/"
    EQ = "=="
    NE = "!="
    GT = ">"
    GE = ">="
    LT = "<"
    LE = "<="


##########################################
# expressions
class Expr:
    pass


class ExprNum(Expr):
    def __init__(self, n: int):
        self.num = n

    def __str__(self):
        return f"{self.num}"


class ExprVar(Expr):
    def __init__(self, var: str):
        self.var = var

    def __str__(self):
        return f"{self.var}"


class ExprBop(Expr):
#表达式函数、比如 a + b、a - b这种式子
    def __init__(self, left: Expr, right: Expr, bop: Bop):
        self.left = left
        self.right = right
        self.bop = bop

    def __str__(self):
        if isinstance(self.left, ExprBop):
            left_str = f"({self.left})"
        else:
            left_str = f"{self.left}"

        if isinstance(self.right, ExprBop):
            right_str = f"({self.right})"
        else:
            right_str = f"{self.right}"

        return f"{left_str} {self.bop.value} {right_str}"# 左 OP 右边


###############################################
# statement
class Stmt:
    def __init__(self):
        self.level = 0

    def __repr__(self):
        return str(self)


class StmtAssign(Stmt):
# 语句函数 比如 x = ?

    def __init__(self, var: str, expr: Expr):
        super().__init__()
        self.var = var
        self.expr = expr

    def __str__(self):
        indent_space = self.level * "\t"
        return f"{indent_space}{self.var} = {self.expr}\n" # a = 式子


class StmtIf(Stmt):
    def __init__(self, expr: Expr, then_stmts: List[Stmt], else_stmts: List[Stmt]):
        super().__init__()
        self.expr = expr
        self.then_stmts = then_stmts
        self.else_stmts = else_stmts

    def __str__(self):
        indent_space = self.level * "\t"

        for stm in self.then_stmts:
            stm.level = self.level + 1

        for stm in self.else_stmts:
            stm.level = self.level + 1

        then_stmts_str = "".join([str(stmt) for stmt in self.then_stmts])
        else_stmts_str = "".join([str(stmt) for stmt in self.else_stmts])

        then_str = (f"{indent_space}if {self.expr} :\n"
                    f"{then_stmts_str}")

        if self.else_stmts:
            return (f"{then_str}"
                    f"{indent_space}else:\n"
                    f"{else_stmts_str}")
        else:
            return then_str

#while语句主要是两个部分,条件、函数体,其中函数体包含多个语句,所以传入的是Stmt类型的语句数组List[Stmt],条件一般是不等式,所以需要ExprBop函数来构建
class StmtWhile(Stmt):
    def __init__(self, expr: Expr, stmts: List[Stmt]):
        super().__init__()
        self.expr = expr
        self.stmts = stmts

    def __str__(self):
        indent_space = self.level * "\t"
        for stmt in self.stmts:
            stmt.level = self.level + 1

        #函数体:把数组里面的stmt数组一条条输出
        stmts_str = "".join([str(stmt) for stmt in self.stmts])

        return (f"{indent_space}while {self.expr}:\n"
                f"{stmts_str}")
        # 返回的结果是 while(条件表达式):换行 函数体


###############################################
# function
class Function:
    def __init__(self, name: str, args: List[str], stmts: List[Stmt], ret: Expr):
        self.name = name
        self.args = args
        self.stmts = stmts
        self.ret = ret

    def __str__(self):
        arg_str = ",".join(self.args)
        for stmt in self.stmts:
            stmt.level += 1

        stmts_str = "".join([str(stmt) for stmt in self.stmts])

        # exercise 1: Finish the magic methods __str__() method to get the
        # desired code-printing result:
        #
        # Your code here:

        return ("def " + self.name + "(" + arg_str + ")\n") + (stmts_str) + ("\treturn ") + str(self.ret)

###############################################
# test
#StmtAssign('s',ExprNum(0)),表达的是 s = 0
# StmtAssign('i', ExprNum(0)), 表达的是 i = 0
# StmtWhile 表达while语句、需要传入条件,当然是传入表达式,就需要ExprBop函数,
#表达while i <= n -3
#ExprBop(左边,右边,操作符)
#ExprBop(i, n-3, <=)
#n-3又需要ExprBop函数来表示,所以是 ExprBop(n,3, -)
#对应好相应的类型,i要写成ExprVar('i'),n写成ExprVar('n'),3写成ExprNum(3),-写成Bop.MIN,<=写成Bop.LE
#所以这个while表达式就是 StmtWhile(ExprBop(ExprVar('i'), ExprBop(ExprVar('n'), ExprNum(3), Bop.MIN), Bop.LE)
#同理IF表达式也是这样分析
test_stmt = [StmtAssign('s', ExprNum(0)),
             StmtAssign('i', ExprNum(0)),
             StmtWhile(ExprBop(ExprVar('i'), ExprBop(ExprVar('n'), ExprNum(3), Bop.MIN), Bop.LE),
                       [StmtAssign('s', ExprBop(ExprVar('s'), ExprVar('i'), Bop.ADD)),
                        StmtAssign('i', ExprBop(ExprVar('i'), ExprNum(1), Bop.ADD)),
                        StmtIf(ExprBop(ExprVar('s'), ExprVar('i'), Bop.GT),
                               [StmtAssign("b", ExprBop(ExprVar('s'), ExprNum(1), Bop.MIN))],
                               [])
                        ]),
             StmtIf(ExprBop(ExprVar('s'), ExprVar('i'), Bop.GT),
                    [StmtAssign("s", ExprBop(ExprVar('i'), ExprNum(1), Bop.MIN))],
                    [StmtAssign("s", ExprBop(ExprVar('i'), ExprNum(1), Bop.ADD))])
             ]

test_func = Function(name='printer_test', args=['n'], stmts=test_stmt, ret=ExprVar('s'))


if __name__ == '__main__':
    # Your code should print:
    #
    # def printer_test(n):
    #     s = 0
    #     i = 0
    #     while i <= (n - 3):
    #         s = s + i
    #         i = i + 1
    #         if s > i:
    #             b = s - 1
    #     if s > i:
    #         s = i - 1
    #     else:
    #         s = i + 1
    #     return s
    #
    print(test_func)

输出结果是:

为了构建具体的执行器,我们首先需要定义内存模型,为此,我们将使用Python的数据类模型。我们在具体的.py文件中定义了一个Python数据类内存,它包含了具体内存的定义。内存操作定义为:

练习2:阅读concrete.py文件中的代码,在继续之前确保您理解了具体的模型数据结构。

#中科大软院-华保健老师的形式化课程笔记、欢迎私信交流~

猜你喜欢

转载自blog.csdn.net/weixin_41950078/article/details/112745090