Page 105 - 《软件学报》2025年第9期
P. 105

4016                                                       软件学报  2025  年第  36  卷第  9  期


                 其中,  le 为左值表达式,   id  为变量名称,   为表达式,   le[e] 在  Solidity  中既可以表示对数组元素的引用, 也可以表示
                                               e
                                                                                   e
                 对映射类型的引用, 当表示对数组元素的引用时, 对               le 求值得到数组首元素的地址, 对   求值得到该元素在数组中
                                                                                          le 求值得到映射类
                 的索引值, 对   le[e] 进行左值表达式求值得到当前元素的地址. 当表示对映射类型的引用时, 对
                 型的地址, 对   e 求值得到映射类型中的       key 的值, 对  le[e] 进行左值表达式求值得到根据       key 值映射到键值对的地址.
                    全局变量的左值表达式操作语义如下:

                                                     getAddr(g,id) = addr
                                                                                                    (E-1)
                                                              l
                                                      p,g,l ⊢ id ⇒ addr
                    规则  (E-1) 表示在全局环境中根据变量名称, 使用函数            getAddr(g,id) = addr 可以直接获取变量在   storage 中的
                 存储位置.

                                                                    l
                                                τ le = array  p,g,l ⊢ le,µ ⇒ (sl,0)
                                          p,g,l ⊢ e,µ ⇒ v  addr = (sl,0)+v·getSize(g,τ le )         (E-2)
                                                                l
                                                    p,g,l ⊢ le[e],µ ⇒ addr
                    规则  (E-2) 表示了获取数组元素存储位置的操作语义, 首先根据                τ le  判断当前  le[e] 的类型是否为数组, 确认当

                 前表达式类型为数组类型后, 先对           le 求左值, 得到数组的首地址在        storage 中的位置. 根据  Solidity  的内存模型可
                                                             (sl,0), 然后对   求右值, 得到元素在数组中的索引值, 最
                                                                        e
                 知, 数组类型总是开启一个新的插槽, 因此得到首地址为
                 终得到元素的实际位置为首地址加上元素的偏移量.

                                                                     l
                                               τ le = mapping  p,g,l ⊢ le,µ ⇒ (sl,0)
                                           p,g,l ⊢ e,µ ⇒ v  keccak256(h(v)·(sl,0)) = addr           (E-3)
                                                                l
                                                    p,g,l ⊢ le[e],µ ⇒ addr
                    规则  (E-3) 表示了映射类型的左值操作语义, 首先根据             τ le  判断类型是否为映射类型, 确认当前表达式类型为
                               le 求左值, 得到映射类型的首地址在         storage 中的位置. 根据  Solidity  的内存模型可知, 映射类型
                 映射类型后, 先对
                                                               e
                 总是开启一个新的插槽, 因此得到首地址为               (sl,0), 然后对   求右值, 得到映射类型的       key  值  v, 其中  keccak256
                 (h(v)·addr)  为哈希计算函数, 得到该键值在      storage 中的地址  addr.

                                          l                                        (    )
                                p,g,l ⊢ le,µ ⇒ (sl,0)  LVs_struct(lv,id) = addr = (sl,0)+field_offset id,φ s id
                                                                                                    (E-4)
                                                                l
                                                    p,g,l ⊢ le.id,µ ⇒ addr
                    规则  (E-4) 描述了获取结构体成员变量存储位置的操作语义.                 le 求左值, 得到结构体在      storage 中的首地址.
                 根据  Solidity  的内存模型可知, 结构体总是开启一个新的插槽, 因此得到首地址为                      (sl,0). 再根据函数  LVs_
                 struct(lv,id)  得到成员变量在  storage 中的偏移量.

                 2.7   右值表达式求值规则
                    Solidity  中的右值表达式定义如下:

                                                    ( )
                                                         ∗
                                                            ∗


                                  e::= constantid le[e]le.ee 1 e |e |unop e|e 1 binop e 2 |le assign e

                                                         2
                    右值表达式操作语义如下:

                                                  l
                                          p,g,l ⊢ le ⇒ addr  load(S,addr,getSize(g,τ le )) = v
                                                                                                    (E-5)
                                                      p,g,l ⊢ le,µ ⇒ v
                    规则  (E-5) 描述了既能够成为左值表达式又能够成为右值表达式的表达式, 如数组类型、结构体类型以及变
                 量名称, 对这些表达式进行右值表达式求值操作语义, 先获取表达式作为左值表达式时求值所得的地址, 再使用函
                 数  load(S,addr,getSize(g,τ le )) 从存储中加载其右值.

                                                            l
                                         τ le = array  p,g,l ⊢ le,µ ⇒ addr 1  p,g,l ⊢ e,µ ⇒ v 1
                                                           v = load(S,addr 2 ,getSize(g,τ le ))     (E-6)
                                      LVs_arr(addr 1 ,v 1 ) = addr 2
                                                     p,g,l ⊢ le[e],µ ⇒ v
   100   101   102   103   104   105   106   107   108   109   110