SMT solver Boolector, Z3, và STP

Một phần của tài liệu Kiểm chứng chương trình dựa trên SMT (Trang 38)

Đối với một công cụ kiểm chứng tự động các SMT solver đóng vai trò quyết định hiệu suất thực hiện của công cụ đó. Trong phần tiếp theo luận văn trình bày một vài SMT solver được đánh giá là mang lại hiệu quả to lớn trong lĩnh vực kiểm chứng phần mềm. Cụ thể, phần tiếp theo trình bày ba SMT solver Boolecter, Z3, STP là những SMT solver được đánh giá cao về tốc độ xử lý trên nền tảng lý thuyết bitvector và mảng mở rộng.

a. Boolecter

Boolector [21] là bộ giải SMT miễn phí rất hiệu quả trên nền tảng lý thuyết không chứa phép lượng tử hóa tồn tại (), mọi () của Bit-Vector kết hợp với lý thuyết mở rộng của mảng. Bit - Vector có thể được sử dụng để thể hiện thiết kế và đặc tả trực tiếp ở mức độ từ (word - level). Trong khi mảng có thể sử dụng để mô hình bộ nhớ. Ví dụ bộ nhớ chính của phần mềm, bộ nhớ phụ (cache) hoặc các thành phần FIFO (First In First Out) của các hệ thống phần cứng. Sự kết hợp giữa Bit - Vector và mảng làm cho lý luận về phần mềm, phần cứng ở mức độ thích hợp hơn so với logic mệnh đề. Boolector cung cấp mô hình cụ thể cho Bit-Vector và mảng. Boolector được đánh giá là SMT solver có hiệu suất thực hiện nhanh hơn so với Z3 khi tham gia cuộc thi giữa các SMT vào năm 2008 và 2009.

Kiến trúc của Boolector được thể hiện trong hình 3.2. Trong đó Boolector phụ thuộc vào việc viết lại và Bit - Blasting cho Bit - Vector và lý thuyết mảng mở rộng. Dữ liệu đầu vào của Boolector là các công thức thuộc định dạng SMT – LIB hoặc định dạng BTOR.

BTOR là định dạng Bit - Vector ở mức thấp với ngữ nghĩa rõ ràng,

dễ phân tích. BTOR cũng hỗ trợ mảng Bit - Vector và kiểm chứng mô hình (model checking) cho các thuộc tính của chương trình. Ngoài ra, Boolector cũng cung cấp một hệ thống API C phong phú cho phép sử dụng Boolector như là một thư viện. Boolector được thực thi trong ngôn ngữ C.

Hình 3.2. Sơ đồ tổng quan của Boolector [21]

- Parser (Bộ phân tích cú pháp): Thành phần này sẽ tiến hành đọc

các giá trị (input) và xây dựng cú pháp trừu tượng dạng một đồ thị có hướng (DAG). Trong quá trình phân tích, những luật viết lại cơ bản được áp dụng để giản hóa đồ thị có hướng này. Boolector có thể phần tích hai định dạng SMT-LIB và BTOR.

- Rewriter (Bộ viết lại): Bộ công cụ cung cấp các luật viết lại để đơn

giản hóa các đầu vào. Nó được chia làm ba cấp độ: Cấp độ 1 là viết

Formula Refinement (Thành phần làm mịn công thức) Uder Aproximation (Thành phần xấp xỉ cơ sở) SAT solver Array Consistency Checker (Bộ kiểm chứng tính nhất quán của mảng) Model Generator (Bộ sinh mô hình) SMT - LIB Parser (Bộ phân tích) BTOR Rewriter (Bộ viết lại) MODEL SAT/UNSAT

lại các luật cơ bản, chẳng hạn ((a ˄ ¬a)   ) được áp dụng trong quá trình xây dựng công thức. Cấp độ 2 là áp dụng luật thay thế các luật phức tạp bằng các thuật ngữ đơn giản bằng kỹ thuật phân tích tĩnh. Tuy nhiên, trước khi được thay thế các luật này sẽ được lưu trữ lại. Cấp độ thực 3 thực hiện chuẩn hóa các biểu thức số học. Trong trường hợp xấu nhất có thể giới hạn độ sâu đệ quy.

- Array Consistency Checker (Bộ kiểm chứng tính nhất quán của

mảng): Bộ kiểm chứng là thành phần chính trong cho cách tiếp cận cho lý thuyết mở rộng không chứa các phép lượng tử hóa của mảng. Nó tiến hành kiểm chứng xem phép gán hiện tại được tạo ra bởi SAT solver xem liệu có nhất quán với lý thuyết.

- Under-approximation: Boolector hỗ trợ kỹ thuật xấp xỉ mức cơ sở

của các biên bit-vector và thao tác đọc (read) trong mảng bit-vector. Thành phần này có trách nhiệm thực hiện xấp xỉ cơ sở trực tiếp từ công thức CNF. Boolector cũng hỗ trợ kỹ thuật xấp xỉ cơ sở và chiến lược làm mịn. Kỹ thuật xấp xỉ cơ sở có thể được làm mịn ở cả mức độ cục bộ và toàn bộ.

- SAT Solver: picoSAT là SAT solver được sử dụng trong

Boolector. Nó sử dụng các kỹ thuật như: duyệt các literal, học các xung đột và khởi động lại nhanh. Boolector sử dụng PicoSAT trong các bước để làm tăng khả năng quyết định cho lý thuyết mở rộng của mảng và xấp xỉ mức cơ sở.

- Model Generator (Bộ sinh mô hình): Là thành phần cung cấp các

mô hình cụ thể trong trường hợp thỏa mãn (SAT). Nhìn chung, một công thức thỏa mãn tương ứng với một lỗi được tìm thấy. Tính năng cung cấp một phản ví dụ cụ thể được trực tiếp sử dụng để gỡ lỗi. Đây là một trong nhưng tính năng chính của kiểm chứng mô hình. Boolector có thể trả về bit-vector cụ thể và các mô hình mảng.

Mô hình mảng là một mảng được khởi tạo trong đó chỉ số và giá trị của phần tử mảng đều là các bit–vector cụ thể.

- Formula Refinement (Bộ làm mịn công thức): Đây là thành phần quan trọng bậc nhất của Boolector. Ban đầu, phần bit–vector được dịch để đưa vào SAT trong khi phần mảng được trừu tượng hóa với các biến bit–vector mới. Việc gọi SAT solver được thực hiện lặp đi lặp lại để tìm một phép gán thỏa mãn. Nếu kết quả là không thỏa mãn thì vòng lặp kết thúc và trả về UNSAT. Tuy nhiên, nếu kết quả là SAT bộ phận kiểm tra tính nhất quán của mảng sẽ được sử dụng để kiểm tra. Nếu phép gán hiện tại là nhất quán thì công thức là thỏa mãn. Tuy nhiên, nếu phép gán hiện tại không nhất quán, một bổ đề theo yêu cầu được bổ sung vào công thức làm mịn.

Nếu Boolector được đánh giá là có tốc độ thực hiện tương đối nhanh thì Z3 lại là SMT solver hỗ trợ nhiều kiểu lý thuyết khác nhau. Phần tiếp theo luận văn sẽ trình bày về SMT solver Z3.

b. Z3

Z3 [15] là SMT solver mới được xây dựng bởi trung tâm nghiên cứu của Microsoft với mục tiêu là giải quyết các vấn đề phát sinh trong kiểm chứng và phân tích phần mềm. Do đó, nó tích hợp hỗ trợ một loạt các lý thuyết.

Việc tương tác với Z3 được thực hiện bằng cách sử dụng định dạng văn bản hoặc sử dụng API nhị phân mà Z3 cung cấp. Ba định dạng văn bản được hỗ trợ là định dạng SMT – LIB [19], định dạng rút gọn, công cụ được đánh giá là khá hiệu quả với đầu vào có thể là định dạng textual hoặc API nhị phân. Ba định dạng đầu vào được hỗ trợ là: SMT- LIB, Simplify, định dạng tự nhiên mức độ thấp trong định dạng DIMACS của công thức mệnh đề SAT. Chúng ta cũng có thể gọi Z3 cho các API ANSI C hoặc các API của .NET.

Z3 dựa trên giải thuật giải SAT DPLL hiện đại. Z3 thực hiện trên code C++. Về cơ bản sơ đồ tổng quan của Z3 được thể hiện trong hình 3.3

Kiến trúc của Z3 được minh họa cụ thể trong hình 3.3.

Hình 3.3 Sơ đồ tổng quan của Z3 [15]

- Thành phần Simplifier (Bộ phận đơn giản hóa biểu thức đầu vào): Việc

xử lý biểu thức đầu vào cần được xử lý đầu tiên. Thành phần này áp dụng loại bỏ biểu thức đại số chuẩn chẳng hạn như: p  true  p. Đồng thời cũng thực hiện luật giản lược theo ngữ cảnh vì nếu nó thỏa mãn với mọi giá trị của biến thì sẽ thỏa mãn với một giá trị cụ thể nào đó. Chẳng hạn, x = 4

SMT - LIB Simplify Native text

Ocaml

C .NET

Simplifier

Complier

Congruence closure core

Theory Solvers Linear arithmetic Bit - vector Arrays Tuples SAT solver E- matching engine Clauses equalities new atoms equalities assignments

 q(x)  x = q(4). Giá trị x = 4 là thỏa mãn, tuy giá trị này không phải là vấn đề quan tâm nhất. Nhưng nó cũng được giữ lại trong trường hợp cần mô hình hóa giá trị của x.

- Complier (Trình biên dịch): Việc biểu diễn cây cú pháp trừu tượng giản

lược được chuyển đổi thành các cấu trúc dữ liệu khác nhau gồm một tập các mệnh đề và nút đẳng thức tương ứng.

- Congruence Closure Core (Lõi đồng dư): Thành phần này nhận một phép

gán giá trị chân trị cho các Atom từ các máy giải SAT (SAT solver). Các Atom thay đổi giá trị trong đẳng thức và lý thuyết đặc tả biểu thức atomic như là bất đẳng thức. kết quả được đánh giá bởi máy giải SAT được lan truyền bằng Congruence Closure Core sử dụng cấu trúc dữ liệu E – graph [7]. Nút trong E – graph có thể trỏ đến một hoặc nhiều máy giải. Khi có hai nút được gộp lại thì máy giải lý thuyết tham chiếu cũng được gộp. Nếu trong quá trình lan truyền giá trị của các atom. Nếu một atom không thể nhận được giá trị trong quá trình lan truyền thì SAT solver sẽ gán cho nó một giá trị bất kì.

- SAT Solver Boolean: SAT solver tích hợp phương thức cắt tỉa không gian

tìm kiếm áp dụng các kỹ thuật đã trình bày trong thuật toán DPLL như lan truyền mệnh đề, học mệnh đề conflict và quay lui…

Z3 đã và đang được sử dụng trong các dự án của Microsoft từ tháng 2 năm 2007. Ứng dụng chính của nó là mở rộng các kiểm chứng tĩnh, quá trình sinh test case và trừu tượng hóa mệnh đề.

c. STP

STP [26] được đánh giá SMT solver hiệu quả và có tốc độ thực thi nhanh so với các SMT solver khác. Đầu vào của STP hầu hết là các hàm, các vị từ được thực thi trong hầu hết các ngôn ngữ lập trình như C, tập lệnh mã máy. Những tập các phép toán được hỗ trợ bao gồm true, false, các biến mệnh đề, phép nối trong biểu thức logic (, , ), các toán tử trên bit, phép dịch trái, phép dịch phải, dịch trái, phép cộng, phép nhân, phép trừ, hàm đọc và ghi mảng. Các

thành phần ngữ nghĩa song song với ngôn ngữ bit – vector SMTLIB. Hoặc ngôn ngữ C, ngoại trừ trường hợp Bit – Vector có chiều dài cực lớn.

STP có thể được sử dụng như một chương trình độc lập hoặc cũng có thể được sử dụng như là một thư viện, nó có một API đặc biệt bằng ngôn ngữ C cho phép nó dễ dàng tích hợp với các ứng dụng khác.

STP chuyển bài toán quyết định trong logic của nó thành mệnh đề dạng CNF giúp tăng hiệu suất giải quyết của máy giải SAT trong nó. Minisat [17] có một hệ thống API tốt, nó ngắn gọn, rõ ràng, hiệu quả, đáng tin cậy và hoàn toàn miễn phí nên không bị ràng buộc bởi điều kiện cấp phép. Cách giải quyết của STP hay ở chỗ Với một công thức đầu vào thay vì chuyển đổi ngay biểu thức sang dạng CNF để gọi máy giải SAT thì nó cố gắng giải các công thức này bằng thành phần solving linear để giải luôn mà chưa cần gọi ngay SAT solver. Như vậy sẽ làm tăng đáng kể hiệu suất. Nghĩa là, tất cả các lý thuyết đặc tả sẽ được xử lý trước khi gọi SAT solver. Sau đó, SAT solver sẽ thực thi trên các công thức mệnh đề thuần túy cái mà đã được trừu tượng hóa. Giúp tối ưu hóa ở mức cao bên trong vòng lặp. Cách thức giải quyết này vừa giúp STP làm việc hiệu quả lại có thể làm giảm độ khó của bài toán.

Tuy nhiên với cách tiếp cận của mình STP không hẳn là SMT solver tốt nhất trong mọi trường hợp. Công thức đầu vào tốt nhất cho STP đó là công thức dạng CNF của các công thức mà cho phép biến đổi đại số cục bộ. Ngược lại, công thức dạng tuyển DNF ở mức độ cao được đánh giá là khó với STP. Cũng rất may, các ứng dụng phần mềm được sử dụng bởi STP có xu hướng tạo ra các công thức CNF lớn. Do đó, cách tiếp cận của STP được đánh giá là tốt trong thực tế. Về kiến trúc của STP được thể hiện trong hình vẽ dưới đây.

Kiến trúc của STP

Kiến trúc của STP được mô phỏng thông qua hình 3.3.

Về kiến trúc của STP solver gồm có ba pha trong phép biến đổi ở mức độ từ.

Pha một hệ thống chuyển đổi từ công thức ở đầu vào thành một công thức trừu tượng dưới dạng Logic mệnh đề.

Pha hai tiến hành đơn giản hóa biểu thức Logic (quy trình này được gọi là Bit Blasting).

Pha ba biến đổi thành công thức lô gíc mệnh đề dạng CNF và giải bằng SAT solver.

Hình 3.4 Sơ đồ kiến trúc của STP solver [26]

Các biểu thức thường được biểu diễn dưới dạng một đồ thị có hướng nó được tạo ra bởi bộ phân tích cú pháp của môi trường C cho đến khi chúng được chuyển thành biểu thức logic dạng CNF. Trong các đồ thị có hướng, cây con đơn (isomorphic) được biểu diễn bởi một nút đơn mà được trở bởi nhiều nút cha. Cách biểu diễn này mang đến cả lợi ích và sự bất lợi. Tuy nhiên, lợi ích nhiều

Refinement Array Axioms Input Formula Substitution simplifications Linnear Solving BitBlast CNF conversion SAT solver SAT UNSAT

hơn. Nó có thể xác định một số nguyên tắc thiết kế mà đã làm việc rất hiệu quả trong sự phát triển của STP. Chẳng hạn, khi gặp những công thức khó biến đổi nếu ta cứ cố gắng biến đổi thì có vẻ không khả thi. Lúc này ta dùng đến các phản ví dụ

Phản ví dụ (counter example) được xem là mô hình tiêu chuẩn cho các công cụ hình thức. Cách tiếp cận này có thể được áp dụng theo nhiều cách khác nhau. Nó là một ứng dụng của nguyên tắc trì hoãn.

Một cách thức thực thi mới của STP đó là việc thực thi riêng đối với từng vòng lặp trong STP như hình 3.4. Trong STP công thức dạng trừu tượng được thực thi mà không quan tâm tới phép biến đổi từ công thức ban đầu sang công thức dạng trừu tượng. Trong đó công thức trừu tượng phải tương đương với công thức ban đầu (hai công thức φ và ψ được gọi là tương đương nếu φ thỏa mãn thực sự thì ψ cũng được thỏa mãn).

Quá trình kiểm tra tính thỏa mãn của một công thức đầu vào gồm 3 giai đoạn.

Giai đoạn một STP solver cố gắng tìm một mô hình của công thức trừu tượng hóa được biến đổi từ công thức ban đầu. Nếu công thức dạng trừu tượng là không thỏa mãn dễ thấy rằng công thức ban đầu là không thỏa mãn STP solver trả ra kết quả UNSAT mà không cần phải tiến hành làm mịn rõ ràng tiết kiệm được một lượng lớn công việc.

Giai đoạn hai STP solver tìm được một phép gán thỏa mãn công thức trừu tượng. Nó tiến hành kiểm tra tính nhất quán của phép gán này trong công thức ban đầu. Nếu kết quả đánh giá là đúng thì khẳng định đó là mô hình của công thức ban đầu (tức là công thức ban đầu là SAT). Quá trình làm việc kết thúc STP solver trả về kết quả SAT.

Giai đoạn ba mô hình mà STP solver tìm được thông qua SAT solver không nhất quán. Trong trường hợp này, STP solver tiếp tục làm mịn công thức trừu tượng bằng kỹ thuật dựa trên kinh nghiệm (heuristic). Nghĩa là thêm một mệnh đề vào công thức CNF và giải công thức này bởi

SAT solver. Quy trình này được lặp cho đến khi một kết quả chính xác được tìm thấy. Lý thuyết mà STP solver hỗ trợ là mảng một chiều được đánh chỉ số bởi bit-vector và chứa các bit–vector.

Trong chương 2 và chương 3 luận văn đã trình bày về thực thi tượng trưng, SAT solver, SMT solver cùng ba SMT solver được đánh giá là hiệu quả trong kiểm chứng chương trình. Những kiến thức được trình bày trong hai chương này là cơ sở để phát triển các công cụ kiểm chứng tự động nói chung và công cụ KLEE nói riêng. Trong chương tiếp theo luận văn sẽ trình bày về công cụ KLEE và trình bày một số bài toán kiểm chứng được thực hiện trên công cụ này.

Chƣơng 4. KIỂM CHỨNG DỰA TRÊN KLEE

Trong chương này, luận văn trình bày công cụ kiểm chứng tự động KLEE, một công cụ sử dụng thực thi tượng trưng động kết hợp với các SMT solver để kiểm chứng một số thuộc tính của chương trình. Một số ứng dụng của KLEE sẽ được trình bày trong chương này bao gồm phát hiện lỗi chia cho không trong chương trình, phát hiện lỗi truy cập ngoài kích thước của mảng.

Một phần của tài liệu Kiểm chứng chương trình dựa trên SMT (Trang 38)

Tải bản đầy đủ (PDF)

(82 trang)