Đặc tả hệ thống trong TVLA

Một phần của tài liệu Nghiên cứu kỹ thuật giải thích trừu tượng (Trang 72)

Chương trình được đặc tả trong TVLA thông qua hai định dạng.

+ TVS (Three Valued logical Structure): mô tả một trạng thái cụ thể của heap sử dụng cấu trúc 3-valued logic. Được sử dụng để đặc tả trạng thái của heap đầu vào và heap đầu ra.

+ TVP (Three Valued Program) chứa định nghĩa các vị từ, các actions. Từ đó kết hợp với CFG để đặc tả ngữ nghĩa thực thi của chương trình. Để đơn giản trong đặc tả, ngữ nghĩa thực thi được chỉ định riêng biệt theo từng loại dữ liệu.

Một quan sát quan trọng là đặc tả TVP luôn được nghĩ thông qua các khái niệm dạng 2-valued hơn là 3-valued: lý thuyết nhúng (Embedding) đảm bảo tính mạnh của việc giải thích lại công thức trong miền trừu tượng. Đây là ứng dụng của giải thích trừu tượng trong phân tích tĩnh, theo đó một phân tích tĩnh luôn bắt đầu với ngữ nghĩa thực thi cụ thể của chương trình.

71 3.4.2. Giới thiệu bài toán

Trong phần thử nghiệm này chúng ta phân tích các chương trình thao tác với danh sách liên kết đơn có cấu trúc như sau.

typedef struct node { struct node *n; int data;

}*L;

Mục tiêu là áp dụng các kỹ thuật giải thích trừu tượng đã trình bày vào phân tích để xác minh các thuộc tính sau.

+ Không thất thoát bộ nhớ (không có phần tử nào tồn tại mà không đạt đến được từ biến của chương trình);

+ Danh sách đầu ra là không chia sẻ (không có phần tử nào bị tham chiếu tới bởi nhiều hơn hai phần tử khác).

Để đơn giản hóa phân tích trong TVLA, các hàm C nguyên bản được tiền xử lý bằng phương pháp sau.

+ Lệnh gán với một trường dữ liệu được thực hiện trung gian qua lệnh gán trường đó bằng giá trị NULL trước. Ví dụ x−> n = y; được thay thế bởi x−> n = NULL; x− > n = y;

+ Các lệnh giải phóng bộ nhớ cũng được thực hiện qua lệnh gán NULL trung gian với các trường giá trị. Ví dụ, free( x); được thay thế bằng x− > n = NULL; free( x);

+ Các lệnh sao chép giá trị từ một trường đến một trường khác được đơn giản bởi việc sử dụng biến trung gian.Ví dụ, x−> n=y−>n

được thay thế bởi t=y−>n; x−>n=NULL; x−>n=t; t=NULL;

Các điều kiện rẽ nhánh trong chương trình được mô hình bởi hai action, một cho nhánh true và một cho nhánh false. [13]

3.4.3. Đặc tả dữ liệu đầu vào

3.4.3.1. Tệp TVS mô tả heap đầu vào

Tệp tin TVS (input.tvs) mô tả các heap đầu vào như sau [13]:

// An acyclic singly-linked list with two or more elements pointed by program x.

72 %n = {head, tail} %p = { sm = {tail:1/2} n = {head->tail:1/2, tail->tail:1/2} x = {head}

t[n] = {head->head, head->tail, tail->tail:1/2} r[n,x] = {head, tail}

}

// An acyclic singly-linked list with a single element pointed by x. %n = {head} %p = { x = {head} t[n] = {head->head} r[n,x] = {head} }

// An empty list (x points to NULL). %n = {}

%p = {}

3.4.3.2. Tệp TVP định nghĩa các vị từ

Tệp tin TVP (predicates.tvp) mô tả các vị từ được sử dụng có nội dung như sau [13]:

// Core Predicates

// For every program variable z there is a unary predicate that holds for

// list elements pointed by z.

// The unique property is used to convey the fact that the predicate can hold

// for at most one individual.

// The pointer property is a visualization hint for graphical renderers.

foreach (z in PVar) {

%p z(v_1) unique pointer }

// The predicate n represents the n field of the list data type.

%p n(v_1, v_2) function acyclic

///////////////////////////////////////////// // Instrumentation (i.e., derived) predicates

// The is[n] predicate holds for list elements pointed by two different

// list elements.

%i is[n](v) = E(v_1, v_2) (v_1 != v_2 & n(v_1, v) & n(v_2, v))

// The t[n] predicate records transitive reflexive reachability between

73

// list elements along the n field.

%i t[n](v_1, v_2) = n*(v_1, v_2) transitive reflexive // Integrity constraints for transitive reachability %r !t[n](v_1, v_2) ==> !n(v_1, v_2)

%r !t[n](v_1, v_2) ==> v_1 != v_2

%r E(v_1) (t[n](v_1, v_2) & t[n](v_1, v_3) & !t[n](v_2, v_3)) ==> t[n](v_3, v_2)

// For every program variable z the predicate r[n,z] holds for individual

// v when v is reachable from variable z along the n field (more formally,

// the corresponding list element is reachable from z). foreach (z in PVar) {

%i r[n,z](v) = E(v_1) (z(v_1) & t[n](v_1, v)) }

3.4.3.3. Tệp TVP định nghĩa các Actions

Tệp tin TVP (actions.tvp) mô tả các actions được sử dụng có nội dung như sau [13]: %action uninterpreted() { %t "uninterpreted" } %action skip() { %t "skip" }

// Actions for statements manipulating pointer variables and pointer fields %action Set_Null_L(lhs) { %t lhs + " = NULL" { lhs(v) = 0 } } %action Copy_Var_L(lhs, rhs) { %t lhs + " = " + rhs %f { rhs(v) } { lhs(v) = rhs(v) } } %action Malloc_L(lhs) { %t lhs + " = (L) malloc(sizeof(struct node)) " %new { lhs(v) = isNew(v)

74 t[n](v_1, v_2) = (isNew(v_1) ? v_1 == v_2 : t[n](v_1, v_2)) r[n, lhs](v) = isNew(v) foreach(z in PVar-{lhs}) { r[n,z](v) = r[n,z](v) } is[n](v) = is[n](v) } } %action Free_L(lhs) { %t "free(" + lhs + ")" %f { lhs(v) }

%message (E(v, v_1) lhs(v) & n(v, v_1)) ->

"Internal Error! " + lhs + "->" + n + " != NULL" { t[n](v_1, v_2) = t[n](v_1, v_2) foreach(z in PVar) { r[n,z](v) = r[n,z](v) } is[n](v) = is[n](v) } %retain !lhs(v) } %action Get_Next_L(lhs, rhs) { %t lhs + " = " + rhs + "->" + n

%f { E(v_1, v_2) rhs(v_1) & n(v_1, v_2) & t[n](v_2, v) } %message (!E(v) rhs(v)) ->

"Illegal dereference to\n" + n + " component of " + rhs { lhs(v) = E(v_1) rhs(v_1) & n(v_1, v) } } %action Set_Next_Null_L(lhs) { %t lhs + "->" + n + " = NULL" %f { lhs(v),

// optimized change-formula for t[n] update-formula E(v_1, v_2) lhs(v_1) & n(v_1, v_2) & t[n](v_2, v) }

%message (!E(v) lhs(v)) -> "Illegal dereference to\n" + n + " component of " + lhs {

75 } } %action Set_Next_L(lhs, rhs) { %t lhs + "->" + n + " = " + rhs %f { lhs(v), rhs(v),

// optimized change-formula for t[n] upate-formula E(v_4) rhs(v_4) & t[n](v_4, v_2)

}

%message (E(v_1, v_2) lhs(v_1) & n(v_1, v_2)) ->

"Internal Error! " + lhs + "->" + n + " != NULL" %message (E(v_1, v_2) lhs(v_1) & rhs(v_2) & t[n](v_2, v_1)) ->

"A cycle may be introduced\nby assignment " + lhs + "->" + n + "=" + rhs

{

n(v_1, v_2) = n(v_1, v_2) | lhs(v_1) & rhs(v_2) }

}

// Actions needed to simulate program conditions involving pointer // equality tests. %action Is_Not_Null_Var(lhs) { %t lhs + " != NULL" %f { lhs(v) } %p E(v) lhs(v) } %action Is_Null_Var(lhs) { %t lhs + " == NULL" %f { lhs(v) } %p !(E(v) lhs(v)) } %action Is_Eq_Var(lhs, rhs) { %t lhs + " == " + rhs %f { lhs(v), rhs(v) } %p A(v) lhs(v) <-> rhs(v) } %action Is_Not_Eq_Var(lhs, rhs) { %t lhs + " != " + rhs %f { lhs(v), rhs(v) } %p !A(v) lhs(v) <-> rhs(v) } ///////////////////////////////////////// // Actions for testing various properties

76

%action Assert_ListInvariants(lhs) { %t "assertListInvariants(" + lhs + ")" %f { lhs(v) }

%p E(v) r[n,lhs](v) & is[n](v)

%message ( E(v) r[n,lhs](v) & is[n](v) ) ->

"The list pointed by " + lhs + " may be shared!" } %action Assert_No_Leak(lhs) { %t "assertNoLeak(" + lhs + ")" %f { lhs(v) } %p E(v) !r[n,lhs](v) %message ( E(v) !r[n,lhs](v) ) ->

"There may be a list element not reachable from variable " + lhs + "!"

}

3.4.3.4. Tệp TVP đặc tả ngữ nghĩa thực thi

Trong phạm vi luận văn này tôi chỉ trình bày việc kiểm tra đối với một hàm trong chương trình gọi là Create(), hàm này tạo một danh sách mới và gắn thêm vào một danh sách đang được trỏ tới bởi x [13].

// Sets %s PVar {x, f} #include "predicates.tvp" %% #include "actions.tvp" %%

// Transition system for a function that creates new list of elements and

// appends them to the list pointed by x.

L1 uninterpreted() L2 // for (i=0; i<size; i++) { L1 uninterpreted() exit L2 Malloc_L(f) L3 // f = malloc(sizeof(struct node)); L3 Set_Next_Null_L(f) L4 // f->n = NULL; L4 Set_Next_L(f, x) L5 // f->n = x; L5 Copy_Var_L(x, f) L1 // x = f; // }

exit Assert_ListInvariants(x) error exit Assert_No_Leak(x) error

Nội dụng đặc tả này được đưa vào tệp create.tvp. 3.4.4. Kết quả phân tích

Để thực hiện phân tích trên TVLA chúng ta thực hiện lệnh sau: tvla create input. Trong đó tvla là từ khóa gọi công cụ phân tích, create là đường dẫn tới tệp create.tvp, input là đường dẫn tới tệp input.tvs.

77

Hình 3.9: Kết quả phân tích hàm tạo danh sách liên kết

Kết quả phân tích được TVLA xuất ra dưới dạng tệp TVS có nội dung được mô tả cụ thể trong phụ lục B.

3.5. Kết luận chương 3

Giới thiệu tổng quan về bộ công cụ mã nguồn mở TVLA trong việc phân tích hình dạng heap chương trình, các cơ sở toán học nền tảng của TVLA . Các kỹ thuật liên quan đến biểu diễn ngữ nghĩa chương trình bằng cấu trúc 2-valued logic, 3-valued logic và phép nhúng giữa hai cấu trúc, quá trình cập nhật công thức vị từ sau mỗi thực thi của chương trình, thuật toán sinh hệ phương trình ràng buộc Coerce và thuật toán tìm điểm cố định Focus để giải các hệ phương trình ràng buộc cũng được nghiên cứu.

78 KẾT LUẬN Nội dung đã đạt được

Về cơ bản đề tài đã tiếp cận được cơ sở lý thuyết ban đầu của kỹ thuật giải thích trừu tượng, các ứng dụng của kỹ thuật này trong việc phân tích tĩnh chương trình nhằm nâng cao chất lượng phần mềm, nắm bắt được các xu hướng phát triển để tiến tới cải tiến kỹ thuật này trên thế giới cũng như ở trong nước. Đề tài tập trung nghiên cứu các vấn đề về biểu diễn ngữ nghĩa chương trình, các phương pháp trừu tượng hóa ngữ nghĩa chương trình thông qua cách biểu diễn ngữ nghĩa dưới nhiều dạng khác nhau.

Trên cơ sở các lý thuyết đã tìm hiểu, đề tài cũng đã tiếp cận được các mô phỏng trừu tượng dựa trên cấu trúc 2-valued logic và 3-valued logic, các thuật toán sinh hệ phương trình ràng buộc Coerce và thuật toán giải hệ phương trình ràng buộc Focus để tìm điểm cố định, phép nhúng cấu trúc 2- valued logic vào trong cấu trúc 3-valued logic để sinh ngữ nghĩa trừu tượng và tiến hành thực nghiệm trên bộ công cụ mã nguồn mở TVLA cho một phân tích chương trình cụ thể được cài đặt bằng ngôn ngữ C.

Một số hạn chế

Trong quá trình nghiên cứu đề tài, bản thân cũng đã rất cố gắng với tham vọng cải tiến về cơ sở lý thuyết và cải tiến công cụ thực nghiệm, nhưng hiện tại chưa thực hiện được với nhiều lý do khác nhau, do việc ứng dụng kỹ thuật này vào thực tế gặp rất nhiều khó khăn, các công cụ hỗ trợ cho kỹ thuật này chỉ dừng lại ở mức thực nghiệm cho nghiên cứu cơ bản.

Hướng nghiên cứu tiếp theo

Cải tiến về mặt cơ sở lý thuyết cho kỹ thuật này để tăng khả năng ứng dụng vào thực tế với lớp các bài toán khác. Cải tiến công cụ thực nghiêm dựa trên các bộ mã nguồn mở TVLA để tăng khả năng phân tích tĩnh tự động cho chương trình, áp dụng vào trong giảng dạy cho sinh viên ngành Công nghệ thông tin tại các trường Đại học, Cao đẳng.

79

TÀI LIỆU THAM KHẢO

[1] M. Sagiv, T. Reps, and R. Wilhelm. Parametric shape analysis via 3- valued logic. ACM Transactions on Programming Languages and Systems (TOPLAS), 24(3):217–298, 2002.

[2] Michael I. Schwartzbach. Lecture Notes on Static Analysis. BRICS, Department of Computer Science University of Aarhus, Denmark 2009. [3] Patrick Cousot, Jer C.Hunsaker. An informal overview of abstract

interpretation. Massachusetts Institute of Technology Department of Aeronautics Astronautics, Course 16.399, 2005.

[4] Patrick Cousot, Radhia Cousot. Abstract Interpretation: A Unified Lattice Model for Static Analysis of Programs by Construction or Approximation of Fixpoints. Conference Record of the Fourth ACM Symposium on Principles of Programming Languages, Los Angeles, California, USA, January 1977. ACM, 1977, pp. 238-252.

[5] Patrick Cousot, Radhia Cousot. Basic concepts of abstract interpretation, Web page maintained by P. Cousot, 2004.

[6] Patrick Cousot, Radhia Cousot. Comapring the Galois Connection and Widening / Narrowing Approaches to Abstract Interpretation. In Maurice Bruynooghe and Martin Wirsing. Proc. 4th Int. Symp. on Programming Language Implementation and Logic Programming (PLILP). LNCS 631. Springer. pp. 269–296, 1992.

[7] Patrick Cousot. Abstract Interpretation Based Formal Methods and Future Challenges. In Informatics, 10 Years Back — 10 Years Ahead, R. Wilhelm (Ed.), Lecture Notes in Computer Science 2000, Springer, pp. 138–156, 2001.

[8] Patrick Cousot. Abstract Interpretation. Web page maintained by P. Cousot, 2008.

80

[9] Patrick Cousot. Constructive Design of a Hierarchy of Semantics of a Transition System by Abstract Interpretation. In Electronic Notes in Theoretical Computer Science, Volume 6, 1997.

[10] Patrick Cousot. Partial Completeness of Abstract Fixpoint Checking. Lecture Notes in Computer Science Volume 1864. Springer Berlin Heidelberg, 2000, pp 1-25.

[11] Roberto Giacobazzi (Università di Verona, Italie), Nicolas Halbwachs (Vérimag, France), Manuel Hermenegildo (IMDEA Software Institute & Technical University of Madrid, Espagne). Static analysis by abstract interpretation of concurrent programs, 2013.

[12] Steve S.Muchnick, Patrick Cousot. Semantic Foundations of Program Analysis. In Program Flow Analysis: Theory and Applications. Prentice- Hall, Inc., Englewood Cliffs, New Jersey, U.S.A., 1981.

[13] T. Lev-Ami and M. Sagiv. Tvla: A framework for kleene logic based static analyses. Master’s thesis, Tel Aviv University, 2000.

81 PHỤ LỤC A:

Phân tích biểu thức có sẵn:

Một biểu thức không bình thường (nontrivial) trong một chương trình là có sẵn (available) tại một điểm trong chương trình nếu giá trị của nó đã được tính toán sẵn trước đó trong khi thực thi. Việc xác định các biểu thức đã có sẵn trước khi thực thi sẽ giúp cho việc tính toán nhanh và đơn giản hơn. Dàn cho phân tích này là tập hợp các biểu thức xảy ra cho tất cả các điểm chương trình và được sắp bởi các tập con đảo ngược (reverse). Đối với mỗi nút v trên CFG tương ứng v trên Dàn L chứa các tập con của các biểu thức với một biến ràng buộc ⟦ ⟧ được đảm bảo luôn luôn có sẵn tại điểm chương trình kế sau nút đó. Ví dụ, biểu thức a + b là có sẵn ở điều kiện trong vòng lặp, nhưng nó không phải là có sẵn tại các phép gán trong vòng lặp. [2]

+ Với mỗi nút entry, có ràng buộc là:

⟦ ⟧ = {}

+ Nếu v chứa một điều kiện E hoặc lệnh return E, khi đó ràng buộc là:

⟦ ⟧ = ⋂ ∈ ( )⟦ ⟧ ∪ ( )

+ Đối với v chứa phép gán = , ràng buộc là:

⟦ ⟧ = ⋂ ∈ ( )⟦ ⟧ ∪ ( ) ↓

Đối với những nút khác, ràng buộc là: ⟦ ⟧ = ⋂ ∈ ( )⟦ ⟧

Với hàm ↓ loại bỏ tất cả các biểu thức có chứa một tham chiếu đến biến , và các hàm exps được định nghĩa là:

( ) = ∅

( ) = ∅

( ) = ∅

( 1 2) = { 1 2} ∪ ( 1) ∪ ( 2)

Với op là phép toán nhị phân bất kỳ. Ta thấy rằng một biểu thức là có

sẵn trong v nếu nó có sẵn từ tất cả các cạnh hoặc được tính toán trong nút v, trừ khi giá trị của nó đã được hủy bởi lệnh gán. Một lần nữa, phía vế phải của những ràng buộc là những hàm đơn điệu [2].

int func() { var x,y,z,a,b; z = a+b; y = a*b; while (y > a+b) { a = a+1; x = a+b;

82 }

}

Ta có 4 biểu thức khác nhau, do đó dàn cho phân tích với chương trình là: = (2{ , ∗ , , }, ⊇)

Ta có sơ đồ luồng của chương trình như sau:

Các ràng buộc được sinh ra như sau:

⟦ ⟧ = {}

⟦ , , , , ; ⟧ = ⟦ ⟧

⟦ = + ⟧ = ( + ) ↓

⟦ = ∗ ⟧ = (⟦ = + ⟧ ∪ ( ∗ )) ↓

83

⟦ = + 1⟧ = (⟦ > + ⟧ ∪ ( + 1)) ↓

⟦ = + ⟧ = (⟦ = + 1⟧ ∪ ( + )) ↓

⟦ ⟧ = ⟦ > + ⟧

Áp dụng thuật toán lặp Chaotic tìm điểm cố định ta thu được nghiệm

nhỏ nhất: ⟦ ⟧ = {} ⟦ , , , , ; ⟧ = {} ⟦ = + ⟧ = { + } ⟦ = ∗ ⟧ = { + , ∗ } ⟦ > + ⟧ = { + , > + } ⟦ = + 1⟧ = {} ⟦ = + ⟧ = { + } ⟦ ⟧ = { + }

Nhận thấy rằng các biểu thức có sẵn tại điểmchương trình kế trước một nút v có thể được tính như ⋂ ∈ ( )⟦ ⟧ . Từ đó, một trình biên dịch tối ưu hóa hệ thống có thể làm chương trình trở nên hiệu quả/đơn giản hơn [2]:

int func(){ var x,y,z,a,b,t; t = a+b; z = t; y = a*b; while (y > t) { a = a+1; t = a+b; x = t; } } PHỤ LỤC B: Kết quả phân tích

// @VERSION@ (built on @DATE@) %location L1 = { %n = {} %p = {} %n = {_1, _0} %p = { inac = {_1:1, _0:1} r[n,x] = {_1:1, _0:1} sm = {_1:1/2}

84 x = {_0:1} n = {_1->_1:1/2, _0->_1:1/2} t[n] = {_1->_1:1/2, _0->_1:1, _0->_0:1} } %n = {_1} %p = { inac = {_1:1} r[n,x] = {_1:1} x = {_1:1} t[n] = {_1->_1:1} } %n = {_1} %p = { inac = {_1:1} f = {_1:1} r[n,f] = {_1:1}

Một phần của tài liệu Nghiên cứu kỹ thuật giải thích trừu tượng (Trang 72)