2020-02-14 東京大学工学部電気電子工学科
2019年度卒業論文本審査報告スライド
坂井・入江研究室 学部4年 高橋光輝
近年、ソフトウェアセキュリティ及びソフトウェア
テスティングの観点から、シンボリック実行を用いた
静的解析の手法が注目されている。
(a, b) => {
let x = a * 2 + 100;
//=> x : a * 2 + 100
let y = x * 3 - b;
//=> y : a * 6 - b + 300
let z = x + y;
//=> z : a * 8 - b + 400
return x + y + z;
//=> a * 16 - b * 2 + 700
}
[Li, 2014] より作成
本研究では、先行研究であるSymJSを踏まえ、
新たにSpiderMonkeyのバイトコードを利用する
手法を提案するとともに、
自動モデル検査および自動反例生成の手法を
このフレームワークに適用する方法を示す。
以下の手順でモデル検査および
反例生成を行う。
仕様
整数 \(x\) と \(y\) が与えられる。
1, 2, 3 のうち \(x\) とも \(y\) とも異なる整数を出力せよ。
制約
本問に対応するモデル仕様は、
一階の論理式を用いて以下のように表現することができる。
この問題に対する正当な実装の例、および
SpiderMonkeyによるそのコンパイル結果を示す。
(x, y) => {
if (x === 1) {
if (y === 2) {
return 3;
} else if (y === 3) {
return 2;
}
} else if (x === 2) {
if (y === 1) {
return 3;
} else if (y === 3) {
return 1;
}
} else if (x === 3) {
if (y === 1) {
return 2;
} else if (y === 2) {
return 1;
}
}
return 0;
};
00000: GetArg 0
00003: One
00004: StrictEq
00005: IfEq 73
00015: GetArg 1
00018: Int8 2
00020: StrictEq
00021: IfEq 39
00031: Int8 3
00034: Goto 63
00044: GetArg 1
00047: Int8 3
00049: StrictEq
00050: IfEq 63
00060: Int8 2
00062: Return
00068: Goto 217
00078: GetArg 0
00081: Int8 2
00083: StrictEq
00084: IfEq 150
00094: GetArg 1
00097: One
00098: StrictEq
00099: IfEq 117
00109: Int8 3
00111: Return
00112: Goto 140
00122: GetArg 1
00125: Int8 3
00127: StrictEq
00128: IfEq 140
00138: One
00139: Return
00145: Goto 217
00155: GetArg 0
00158: Int8 3
00160: StrictEq
00161: IfEq 217
00171: GetArg 1
00174: One
00175: StrictEq
00176: IfEq 194
00186: Int8 2
00188: Return
00189: Goto 217
00199: GetArg 1
00202: Int8 2
00204: StrictEq
00205: IfEq 217
00215: One
00216: Return
00222: Zero
00223: Return
00224: RetRval
先に示した実行パスでは、4つの分岐命令を通過している。
これらの分岐条件はそれぞれ \(x\neq1,x=2,y\neq1,y=3\) と
表現できる。
これと先のモデル仕様記述を組み合わせ、反例生成式
を得る。
以上の条件を SMT-LIB 2.0 の
形式で書き下したのが
左の記述である。
これをSMTソルバCVC4を
用いて解くことによって
「充足不可能」の結果を得た。
反例が存在しない、
すなわち与えたプログラムが
モデル記述に対する
正当な実装であることが
保証された。
(set-logic ALL)
(set-option :produce-models true)
(define-sort FP () (_ FloatingPoint 11 53))
(define-fun toFP ((n Real)) FP ((_ to_fp 11 53) RNE n))
(declare-const x FP)
(declare-const y FP)
(assert
(and
(fp.gt x (toFP 0))
(fp.leq x (toFP 3))
(fp.eq (fp.roundToIntegral RNE x) x)
(fp.gt y (toFP 0))
(fp.leq y (toFP 3))
(fp.eq (fp.roundToIntegral RNE y) y)
(not (fp.eq x (toFP 1)))
(fp.eq x (toFP 2))
(not (fp.eq y (toFP 1)))
(fp.eq y (toFP 3))
(not (fp.eq x y))
(not
(let ((ans (toFP 1)))
(and
(fp.gt ans (toFP 0))
(fp.leq ans (toFP 3))
(fp.eq (fp.roundToIntegral RNE ans) ans)
(not (fp.eq ans x))
(not (fp.eq ans y)))))))
(check-sat)
(get-model)
以上の分析をJavaScriptプログラムに対して自動で行う
モデル検査機を実装した。
実験にはプログラミングコンテストAtCoderへの提出プログラムをスクレイピングして用いた。
AtCoderで過去に開催されたプログラミングコンテストの問題から検証に適していると思われるものを選択し、これらの要求仕様を SMT-LIB 2.0 の形で書き下した。
またそれぞれの問題に対するJavaScriptによる提出プログラムをスクレイピングし、実装したモデル検査機への入力として与える。
JavaScriptプログラムのシンボリック実行を用いたプログラム解析という問題に対して、
新たにSpiderMonkeyを用いてバイトコードの適用を行う手法を示した
また、さらにこの手法がJavaScriptプログラムの
モデル検査に応用できることを示した
今後の展望としては、文字列型やオブジェクト型などのより高度なデータ型に対するシンボリック実行を実装し、さらに多くのJavaScriptプログラムを解析できるようにすることが考えられる
(x, y) => {
const z = x + y;
return 6 - z;
};
この例では条件分岐を
含まないため、
実行パスに対応する分岐条件は存在しない。
出力に入力に基づく
シンボルが含まれるため
これを含めてSMTソルバで
求解する。
実行すると同じく
「充足不可能」の結果を得る
(set-logic ALL)
(set-option :produce-models true)
(define-sort FP () (_ FloatingPoint 11 53))
(define-fun toFP ((n Real)) FP ((_ to_fp 11 53) RNE n))
(declare-const x FP)
(declare-const y FP)
(assert
(and
(fp.gt x (toFP 0))
(fp.leq x (toFP 3))
(fp.eq (fp.roundToIntegral RNE x) x)
(fp.gt y (toFP 0))
(fp.leq y (toFP 3))
(fp.eq (fp.roundToIntegral RNE y) y)
(not (fp.eq x y))
(not
(let ((ans (fp.sub RNE (toFP 6) (fp.add RNE x y))))
(and
(fp.gt ans (toFP 0))
(fp.leq ans (toFP 3))
(fp.eq (fp.roundToIntegral RNE ans) ans)
(not (fp.eq ans x))
(not (fp.eq ans y)))))))
(check-sat)
(get-model)