1. Trang chủ
  2. » Luận Văn - Báo Cáo

Nâng cao chất lượng phần mềm bằng các kỹ thuật program slicing

52 2 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Nâng Cao Chất Lượng Phần Mềm Bằng Các Kỹ Thuật Program Slicing
Tác giả Nguyễn Sỹ Linh
Người hướng dẫn Thạc sĩ Nguyễn Trịnh Đông
Trường học Trường Đại Học Dân Lập Hải Phòng
Chuyên ngành Công nghệ thông tin
Thể loại đồ án tốt nghiệp
Thành phố Hải Phòng
Định dạng
Số trang 52
Dung lượng 1,53 MB

Cấu trúc

  • Chương 1: CÁC KHÁI NIỆM CƠ BẢN TRONG PROGRAM SLICING (16)
    • 1.1 Các định nghĩa (16)
    • 1.2 Static slicing (17)
    • 1.3 Dynamic slicing (18)
  • Chương 2: CÁC KĨ THUẬT DÙNG TRONG PHƯƠNG PHÁP STATIC SLICING (20)
    • 2.1. Static slicing đơn thủ tục (20)
      • 2.1.1. Slicing dựa vào đồ thị luồng điều khiển (20)
      • 2.1.2. Slicing dựa vào đồ thị phụ thuộc (23)
    • 2.2. static slicing đa thủ tục (26)
      • 2.2.1. Slicing dựa theo đồ thị luồng điều khiển (26)
      • 2.2.2. Đồ thị phụ thuộc (29)
  • Chương 3: CÁC KỸ THUẬT DÙNG TRONG PHƯƠNG PHÁP DYNAMIC (36)
    • 3.1: Phương thức dynamic chương trình đơn thủ tục (36)
      • 3.1.1: Các khái niệm luồng động (36)
      • 3.1.2. Đồ thị phụ thuộc (39)
    • 3.2. Dynamic slicing đa thủ tục (42)
  • Chương 4: THỰC NGHIỆM TRÊN CÁC CHƯƠNG TRÌNH SLICER (44)
    • 4.1 Chương trình StaticSlicer (44)
    • 4.2. Chương trình Kaveri (47)
  • KẾT LUẬN (15)
  • TÀI LIỆU THAM KHẢO (52)

Nội dung

CÁC KHÁI NIỆM CƠ BẢN TRONG PROGRAM SLICING

Các định nghĩa

Định nghĩa 1: Đồ thị có hướng G Đồ thị có hướng G là một cặp có thứ tự G:=(V, A), trong đó:

- V, tập các đỉnh hoặc nút,

Trong lý thuyết đồ thị, các cặp có thứ tự chứa các đỉnh được gọi là các cạnh có hướng hoặc cung Một cạnh e = (x, y) được xác định là có hướng từ x tới y, trong đó x là điểm đầu (gốc) và y là điểm cuối (ngọn) Định nghĩa này là cơ sở để hiểu về đồ thị luồng điều khiển.

Đồ thị luồng điều khiển (CFG) của chương trình P là một cấu trúc đồ thị trong đó mỗi nút đại diện cho một câu lệnh trong chương trình, và các cạnh biểu thị luồng điều khiển giữa các câu lệnh CFG bao gồm hai nút đặc biệt: Start, biểu thị cho điểm bắt đầu, và Stop, đại diện cho điểm kết thúc của chương trình.

Với câu lệnh thứ n và biến v, một slice S của chương trình P theo tiêu chuẩn slicing(n, v) là một chương trình thực thi bất kỳ có các đặc điểm nhất định.

- S có thể thu đƣợc bằng cách không xoá hoặc xoá nhiều câu lệnh từ

- Khi P dừng với một đầu vào cho trước thì S cũng phải dừng với đầu vào đó, P và S cùng tính toán ra một giá trị của các biến trong

V khi câu lệnh tương ứng với nút n được thực hiện

Static slicing

Theo Weiser, static slicing được xác định bằng cách phân tích các tập hợp biến liên quan của các câu lệnh dựa trên phụ thuộc dữ liệu và luồng điều khiển Phương pháp này chỉ sử dụng thông tin tĩnh, tức là chỉ xem xét mã nguồn mà không quan tâm đến quá trình thực thi chương trình Do đó, các slices trong phương pháp của Weiser được gọi là static slicing.

Một phương pháp khác của Ottenstein sử dụng đồ thị phụ thuộc chương trình

PDG (Program Dependence Graph) là một đồ thị có hướng, trong đó các đỉnh đại diện cho các câu lệnh và tính chất điều khiển, còn các cạnh thể hiện sự phụ thuộc dữ liệu và điều khiển giữa các câu lệnh Tiêu chuẩn slicing được xác định bởi một đỉnh trong PDG, mà từ đỉnh này, các slices slicing sẽ bao gồm tất cả các đỉnh có thể tiếp cận được.

Bergeretti và Carre đã đề xuất một phương pháp mới sử dụng quan hệ luồng thông tin từ chương trình hướng cú pháp Phương pháp này tính toán tập hợp các câu lệnh và xác định điều khiển bằng cách duyệt ngược từ tiêu chuẩn slicing, dẫn đến việc tạo ra các slices gọi là static slicing ngược Họ cũng giới thiệu static slicing tiến, bao gồm tất cả các câu lệnh và tính chất điều khiển phụ thuộc vào tiêu chuẩn slices Một câu lệnh được coi là phụ thuộc vào tiêu chuẩn slices nếu giá trị được tính toán tại câu lệnh đó phụ thuộc vào giá trị tại tiêu chuẩn slices, hoặc nếu giá trị tại tiêu chuẩn slices quyết định sự thi hành của câu lệnh đó.

Hình 1: (a) Chương trình mẫu, (b) slice slicing của chương trình với tiêu chuẩn (10, product)

Static slicing giúp xác định các phần của chương trình có khả năng ảnh hưởng đến kết quả của các chức năng đã chọn cho tất cả các đầu vào có thể Công cụ này rất hữu ích để hiểu rõ hơn về các thành phần của chương trình đóng góp vào tính toán Tuy nhiên, mặc dù có nhiều lợi ích trong việc theo dõi chương trình, static slicing thường dẫn đến các chương trình con lớn do tính toán không chính xác của các slice Hơn nữa, static slicing không thể áp dụng trong quá trình theo dõi hiệu suất thực tế của chương trình.

Dynamic slicing

Khái niệm dynamic slicing, được giới thiệu bởi Kroel và Laski, là một biến thể của phương pháp phân tích luồng ngược của Balzer, tập trung vào luồng thông tin trong chương trình với một giá trị đầu vào cụ thể Người dùng có thể duyệt đồ thị biểu diễn sự phụ thuộc điều khiển và dữ liệu giữa các câu lệnh, ví dụ, nếu giá trị tại câu lệnh n phụ thuộc vào giá trị tại câu lệnh t, người dùng sẽ cần duyệt ngược từ đỉnh tương ứng với câu lệnh n đến đỉnh của câu lệnh t.

Lịch sử thực hiện là chuỗi các câu lệnh và thuộc tính điều khiển trong chương trình Phương pháp dynamic slicing chỉ xem xét các phụ thuộc trong một lịch sử thực hiện cụ thể, tạo ra một slice với bộ ba (x, Iq, V), trong đó x là đầu vào, Iq là câu lệnh thứ q, và V là tập hợp các biến Sự khác biệt giữa static slicing và dynamic slicing nằm ở chỗ dynamic slicing phụ thuộc vào đầu vào cụ thể, trong khi static slicing không quan tâm đến yếu tố này.

Hình 2: (a) chương trình mẫu, (b) Dynamic slicing với tiêu chuẩn (n=2, 8 1 , x)

Trong Hình 2, slice dynamic slicing của chương trình mẫu được thể hiện với tiêu chuẩn slicing C = (n = 2, 8 1 , x), trong đó 8 1 biểu thị lần xuất hiện đầu tiên của câu lệnh 8 trong lịch sử thực hiện Với đầu vào n = 2, thứ tự thực hiện các câu lệnh của chương trình là {1 1 , 2 2 , 3 3 , 4 4 , 6 5 , 7 6 , 3 7 , 4 8 , 5 9 , 7 10 , 3 11}.

Trong đoạn mã, các chỉ số cho biết thứ tự thực hiện của các câu lệnh, với câu lệnh số 8 xuất hiện lần đầu ở vị trí thứ 12 Khi đầu vào n = 2, vòng lặp thực hiện hai lần với các phép gán x: = 18 và x: = 17 Trong lần lặp thứ hai, phép gán x: = 17 thay thế cho phép gán x: = 18 thực hiện trong lần lặp đầu tiên, dẫn đến việc câu lệnh gán x: = 18 không có trong slice slicing Đồng thời, slice static slicing được thiết lập theo tiêu chuẩn C.

(8, x) bao gồm toàn bộ chương trình.

CÁC KĨ THUẬT DÙNG TRONG PHƯƠNG PHÁP STATIC SLICING

Static slicing đơn thủ tục

2.1.1 Slicing dựa vào đồ thị luồng điều khiển

Phương pháp static sling dựa trên đồ thị luồng điều khiển được giới thiệu bởi

Weiser đã đề xuất một tiêu chuẩn slice trong phương pháp phân tích mã nguồn, được định nghĩa bởi bộ C=(n, V), trong đó n là một nút trong đồ thị luồng điều khiển (CFG) của chương trình và V là tập hợp các biến liên quan Một slice S tương ứng với tiêu chuẩn C là tập hợp các câu lệnh trong chương trình P, đảm bảo rằng khi P dừng với một giá trị đầu vào nhất định, S cũng dừng và cả hai cùng tính toán giá trị của các biến trong V khi thực hiện câu lệnh tại nút n Đồ thị CFG là một đồ thị có hướng, với mỗi nút đại diện cho một câu lệnh hoặc thuộc tính điều khiển trong chương trình, và các cạnh thể hiện luồng điều khiển giữa các nút CFG bao gồm hai nút đặc biệt: Start và Stop, tương ứng với điểm bắt đầu và kết thúc của chương trình Tại mỗi nút i, có hai tập hợp các thông tin quan trọng cần được phân tích.

Tập DEF (i) bao gồm tất cả các biến mà giá trị của nó bị thay đổi tại nút i

Tập REF(i) bao gồm tất cả các biến đƣợc tham chiếu tại nút i

Trong đồ thị luồng điều khiển, luồng điều khiển được chia thành hai loại chính: phụ thuộc dữ liệu và phụ thuộc điều khiển Nút j được coi là phụ thuộc vào luồng của nút i khi tồn tại một biến x, thỏa mãn điều kiện x DEF(i) và x REF(j).

Tồn tại một đường đi từ i đến j mà không có sự ghi dữ liệu lên biến x

Trong đồ thị CFG, nút i được coi là nút cha của nút j nếu mọi đường đi từ nút i đến nút Stop đều phải đi qua nút j Đồng thời, nút j được xác định là phụ thuộc điều khiển vào nút i.

Tồn tại một đường đi P từ i đến j mà có u ≠ i, j trong P là cha của j i không phải là cha của j

Trong chương trình có cấu trúc thì các câu lệnh trong các nhánh của câu lệnh if và while là phụ thuộc điều khiển vào tính chất điều khiển

Hình 3 minh họa CFG của chương trình trong Hình 1(a), trong đó nút 7 phụ thuộc luồng vào nút 4 do nút 4 định nghĩa biến product, và nút 7 tham chiếu đến biến này qua đường đi 4 5 6 7 mà không có định nghĩa biến product Đồng thời, nút 7 cũng phụ thuộc điều khiển vào nút 5 vì có đường đi 5 6 7, trong đó nút 6 là cha của nút 7, trong khi nút 5 không phải là cha của nút 7.

Slicing nhỏ nhất được xác định bằng cách phân tích các biến liên quan tại từng nút trong đồ thị CFG Đầu tiên, các biến liên quan trực tiếp được xác định thông qua việc lấy ra các phụ thuộc dữ liệu Ký hiệu i CFG j biểu thị sự tồn tại của một cạnh trong CFG từ nút i đến nút j.

Với tiêu chuẩn cắt C = (n, V), các biến liên quan trực tiếp tại nút i của đồ thị CFG được ký hiệu là (i) Để xác định các biến này, ta tiến hành duyệt ngược đồ thị CFG nhằm tìm ra mối quan hệ giữa các biến Tập hợp các biến liên quan sẽ được xác định như sau:

Với mọi i CFG j, R C 0 (i) chứa tất cả các biến v sao cho v R C 0 (j) và v DEF(i), hoặc v REF(i) và DEF(i) ∩ R C 0 (j) ≠ φ

Tập các câu lệnh liên quan trực tiếp S k+1 C là một tập các nút i xác định một biến v liên quan tại nút liền kề sau j và i trong CFG:

Các biến được tham chiếu trong điều kiện của câu lệnh if hoặc while có mối liên hệ gián tiếp, miễn là có ít nhất một câu lệnh trong thân của chúng liên quan đến các biến đó.

Hình 3: Đồ thị CFG của chương trình mẫu trong Hình 1(a)

Tầm ảnh hưởng IFNL(b) của câu lệnh nhánh b được xác định là liên quan gián tiếp nếu tồn tại nút i, và i nằm trong tầm ảnh hưởng IFNL(b) của b Các câu lệnh nhánh có mối liên hệ với nhau thông qua ảnh hưởng của chúng lên nút i, điều này được xác định rõ ràng.

Tập các biến liên quan gián tiếp S k+1 C chứa các nút trong B k C cùng với nút i xác định một biến liên quan đến một liền kề sau j:

Các tập R k+1 C và S k+1 C là các tập không giảm lần lượt của các biến và câu lệnh trong chương trình Quá trình tính toán tiếp tục cho đến khi S k+1 C đạt trạng thái cố định Các câu lệnh trong S k+1 C là những câu lệnh nằm trong slice slicing mà chúng ta mong muốn.

Hình 4: Kết quả của thuật toán của Weiser với chương trình trong Hình 2(a) và slice slicing với tiêu chuẩn C = (10, product)

Thuật toán static program slicing sử dụng đồ thị luồng dữ liệu của Weiser tính toán ra slice static slicing theo các bước sau:

Bước 1: Xác định các cạnh phụ thuộc luồng và phụ thuộc điều khiển để vẽ đồ thị luồng điều khiển cho chương trình

Bước 2: Xác định các tập biến và các câu lệnh liên quan trực tiếp và gián tiếp đến câu lệnh và biến trong câu lệnh slice bằng cách tính toán các tập hợp R0C, S0C, Rk+1C và Sk+1C.

Để tính toán tập cố định S k+1 C, hãy lặp lại các bước tính toán các tập liên quan đã thực hiện ở bước 2 Các câu lệnh trong S k+1 C bao gồm những câu lệnh nằm trong slice của chương trình slicing mà bạn mong muốn.

Trong ví dụ 2.1.1.2, chương trình được phân tích theo tiêu chuẩn slice(10, product), với các tập DEF, REF, INFL và các biến liên quan được xác định theo thuật toán của Weiser Đồ thị CFG của chương trình cho thấy S0C = {2, 4, 7, 8}, B0C = {5}, và S1C = {1, 2, 4, 5, 7, 8} Tập cố định của các câu lệnh liên quan gián tiếp S1C tương ứng với slice program slicing trong hình 1(b) Câu lệnh write(product) không nằm trong slice slicing do DEF của nó rỗng, không có câu lệnh nào phụ thuộc dữ liệu vào nó, và không có câu lệnh nào phụ thuộc điều khiển vào câu lệnh xuất.

2.1.2.Slicing dựa vào đồ thị phụ thuộc

Ottenstein đã phát triển kỹ thuật static program slicing đơn thủ tục dựa trên đồ thị phụ thuộc chương trình Trong đó, các câu lệnh của chương trình được biểu diễn dưới dạng các đỉnh của đồ thị phụ thuộc, với các cạnh thể hiện mối quan hệ phụ thuộc dữ liệu và điều khiển giữa các câu lệnh Đồ thị PDG của chương trình P, ký hiệu là G_P, là một đồ thị có hướng mà các đỉnh của G_P đại diện cho các câu lệnh và tính chất điều khiển trong chương trình G_P bao gồm một đỉnh đặc biệt gọi là đỉnh vào và có thể có nhiều hơn một cạnh giữa hai đỉnh do tính chất đa đồ thị Các cạnh phụ thuộc điều khiển trong G_P được ký hiệu là u c v, nếu u là đỉnh vào và v là một câu lệnh không nằm trong vòng lặp hay điều kiện Cạnh này được gán nhãn True Nếu u là tính chất điều khiển và v là câu lệnh nằm trong vòng lặp hoặc điều kiện do u biểu diễn, cạnh u c v cũng được gán nhãn True, trong trường hợp u là tính chất của vòng lặp while hoặc được gán nhãn True hay False tùy theo v nằm trong nhánh then hay else của câu lệnh điều kiện.

Cạnh phụ thuộc dữ liệu từ đỉnh u đến đỉnh v cho thấy rằng việc tính toán của chương trình có thể bị thay đổi nếu thứ tự của các thành phần đại diện cho u và v bị đảo ngược Các cạnh phụ thuộc dữ liệu trong đồ thị phụ thuộc chương trình (PDG) được xác định thông qua phân tích luồng dữ liệu Một PDG sẽ có một cạnh phụ thuộc luồng từ đỉnh u đến đỉnh v, ký hiệu là u f v, nếu nó đáp ứng các điều kiện nhất định.

1 u là đỉnh định nghĩa biến x

2 v là một đỉnh sử dụng biến x

3 Đường đi từ u đến v không có định nghĩa nào của x

Các phụ thuộc luồng được phân loại thành hai loại chính: lặp mang và lặp độc lập Một phụ thuộc luồng lặp mang giữa hai biến u và v, ký hiệu là u lc(L) v, được truyền bởi vòng lặp L, cần phải thỏa mãn ba điều kiện cơ bản cùng với các điều kiện bổ sung khác.

4 Có một đường đi thỏa mãn điều kiện thứ (3)bên trên và bao gồm một cạnh ngƣợc đến tính chất điều khiển của vòng lặp L

5 Cả hai u và v đều nằm trong vòng lặp L

Một phụ thuộc luồng u f v là lặp độc lập kí hiệu là u li v ngoài các điều kiện

(1), (2), (3) bên trên thì phải thỏa mãn thêm các điều kiện sau:

6 Có một đường đi thỏa mãn điều kiện thứ (3)ở trên và không có cạnh ngƣợc đến tính chất điều khiểu của vòng lặp L

7 Cả hai u và v đều nằm trong vòng lặp L

static slicing đa thủ tục

2.2.1.Slicing dựa theo đồ thị luồng điều khiển

Weiser chỉ ra hai bước để tính toán slice program slicing đa thủ tục dựa theo đồ thị luồng điều khiển nhƣ sau:

Trong chương trình có nhiều thủ tục, việc tính toán slice slicing được thực hiện với thủ tục P chứa tiêu chuẩn slicing ban đầu Ảnh hưởng của lời gọi thủ tục đến tập các biến liên quan được xác định thông qua thông tin tổng hợp đa thủ tục Đối với thủ tục P, thông tin này bao gồm tập MOD(P) của các biến bị thay đổi.

P và tập USE(P) bao gồm các biến mà P sử dụng Khi gọi thủ tục P, mọi biến trong MOD(P) được xác định và mọi biến trong USE(P) được sử dụng, với tham số thực thay thế cho tham số hình thức Tuy nhiên, thuật toán của Weiser không chính xác vì nó dựa vào các câu lệnh mà tham số ra phụ thuộc vào tham số vào.

Trong Hình 8(a), một chương trình mẫu được trình bày để minh họa vấn đề liên quan đến thuật toán slicing đa thủ tục Thuật toán này sẽ xác định slice slicing, được thể hiện trong Hình 8(b), thông qua việc sử dụng các tập MOD(P) và USE(P) Slice slicing này bao gồm câu lệnh a, do sự phụ thuộc giả giữa biến a trước lời gọi và biến d sau lời gọi.

Hình 8: (a)Chương trình mẫu (b)Slice slicing theo weiser (c)Slice slicing theo HRB

Bước hai: Tiêu chuẩn slicing mới được sinh ra cho hai loại thủ tục: (i) những thủ tục Q đƣợc gọi bởi P và (ii) những thủ tục R gọi đến P

Bước hai sẽ tiếp tục lặp lại cho đến khi không còn tiêu chuẩn mới nào được sinh ra Việc sinh ra các tiêu chuẩn mới được thể hiện qua công thức UP(C) và DOWN(C), ánh xạ tập tiêu chuẩn C trong thủ tục P đến các tập tiêu chuẩn trong các thủ tục R và Q mà P gọi đến.

Tập UP(C) bao gồm các cặp {(n Q , v Q )}, trong đó n Q là câu lệnh cuối cùng của Q và v Q là biến liên quan trong P, nằm trong phạm vi ảnh hưởng của Q, đại diện cho tham số hình thức thay thế cho tham số thực Tương tự, tập DOWN(C) chứa các cặp {(n R , v R )}, với n R là một lời gọi P trong R và v R là tập biến liên quan trong câu lệnh đầu tiên của P, trong tầm ảnh hưởng của R, đại diện cho tham số thực thay thế cho tham số hình thức Tập kín (UP DOWN)*(C) cung cấp các tiêu chuẩn slicing cần thiết để tính toán một slice slicing dựa trên tiêu chuẩn slicing ban đầu C Việc slicing chương trình theo tập tiêu chuẩn này sẽ tạo ra slice program slicing mong muốn.

Hình 9: Chương trình có cấu trúc đa thủ tục mẫu

Trong ví dụ 2.2.1.2, việc slice slicing được thực hiện dựa trên giá trị cuối của biến product trong chương trình như thể hiện ở Hình 9 Nếu tiêu chuẩn ban đầu là (10, product), thì trong bước 1 của thuật toán Weiser, slice slicing sẽ bao gồm tất cả các dòng của chương trình Main, ngoại trừ dòng 3 và dòng 6 Lời gọi thủ tục Multiply(product, i) là một phần quan trọng trong quá trình này.

Hàm Add(i, 1) xuất hiện trong slice slicing do các biến product và i liên quan đến các lời gọi thủ tục, đồng thời thông qua phân tích luồng thông tin đa thủ tục, ta có thể xác định MOD(Add).

Trong chương trình Main, tiêu chuẩn ban đầu được xác định là UP({10, product}) = DOWN({10, product}), bao gồm các tiêu chuẩn (11, {a}) và (17, {c, d}) Kết quả từ việc cắt thủ tục Add với tiêu chuẩn (11, {a}) và thủ tục Multiply với tiêu chuẩn (17, {c, d}) là cả hai thủ tục này Đặc biệt, các lời gọi Add ở dòng 15 và 16 tạo ra tiêu chuẩn mới (11, {a, b}), sau đó thực hiện lại việc cắt thủ tục Add.

Horwitz, Reps và Binkley đã chỉ ra rằng phương pháp slicing đa thủ tục của Weiser không chính xác do gặp vấn đề về ngữ cảnh gọi Vấn đề này xảy ra khi tính toán các thủ tục Q được gọi bởi thủ tục P.

Khi duyệt ngược đồ thị luồng điều khiển, mọi thủ tục gọi Q sẽ được đi lên, không chỉ riêng P Điều này tương đương với việc có các đường thực hiện vào Q từ P và ra Q từ một thủ tục P’ khác Tuy nhiên, các đường thực hiện này không thể thực thi, dẫn đến việc phương pháp slicing tạo ra slice không chính xác.

Trong Hình 9, vấn đề ngữ cảnh gọi được thể hiện rõ ràng Khi dòng 11 xuất hiện trong slice slicing, một tiêu chuẩn mới được tạo ra cho tất cả các lời gọi đến hàm Add Các lời gọi này bao gồm các dòng 8, 15, 16 và lời gọi Add(sum, i) ở dòng 6 Tiêu chuẩn mới (6, {sum, i}) sẽ đưa các câu lệnh 3 và 6 vào trong slice slicing, từ đó tạo ra một slice slicing bao gồm toàn bộ chương trình.

Vấn đề ngữ cảnh gọi của thuật toán Weiser được giải quyết khi các tiêu chuẩn trong tập UP chỉ được xem xét khi có thủ tục gọi đến thủ tục P chứa tiêu chuẩn khởi tạo Nếu không có thủ tục nào gọi đến P, chỉ cần tập DOWN để tính toán slicing.

Hình 10: Chương trình mẫu mà thủ tục P bị slicing n lần với thuật toán của

Ví dụ 2.2.1.4: Trong Hình 10, L kí hiệu cho số dòng của câu lệnh write(z) và

M là số dòng câu lệnh cuối của thủ tục P Tính toán slice slicing với tiêu chuẩn (L,

Trong vòng lặp while, yêu cầu n vòng lặp được thực hiện, trong đó ở vòng lặp thứ i, các biến x1, …, xi sẽ liên quan đến đỉnh gọi gây ra tiêu chuẩn (m, {y1, …, yi}) trong DOWN(Main) Nếu không chú ý khi lấy nhóm tiêu chuẩn, có thể dẫn đến những sai sót không mong muốn.

DOWN(Main) thì thủ tục P sẽ bị slicing n lần

Horwitz, Reps và Binkley áp dụng phương pháp slicing dựa trên đồ thị phụ thuộc hệ thống (SDG) để phân tích chương trình đa thủ tục có cấu trúc Khái niệm "hệ thống" trong SDG nhấn mạnh rằng chương trình có nhiều thủ tục Một SDG bao gồm đồ thị phụ thuộc dữ liệu (PDG) của chương trình chính và các đồ thị phụ thuộc thủ tục, được kết nối bởi các cạnh phụ thuộc lường và điều khiển giữa các thủ tục Mỗi lệnh gọi tương ứng với một đỉnh gọi trong SDG, trong đó tham số truyền được thể hiện qua bốn loại đỉnh tham số Đối với thủ tục gọi, tham số được biểu diễn bằng đỉnh thực trong và ngoài, trong khi đối với các thủ tục được gọi, tham số được thể hiện qua đỉnh hình thức trong và ngoài, cho thấy sự sao chép các biến thực và hình thức từ các biến tạm, phụ thuộc vào các đỉnh gọi.

Tại các câu lệnh gọi thủ tục thì các tham số truyền theo tham trị đƣợc xây dựng theo các bước sau:

Thủ tục gọi sao chép các tham số thực trong của nó đến các biến tạm trước khi gọi nó

Các tham số hình thức trong của thủ tục gọi được khởi tạo tương ứng với các biến tạm

Trước khi trở lại, thủ tục được gọi sao chép giá trị cuối cùng của tham số hình thức ngoài đến các biến tạm

Sau khi trở lại, thủ tục cập nhật các tham số thực bên ngoài bằng cách sao chép giá trị tương ứng vào các biến tạm Đồ thị phụ thuộc thủ tục tạo thành một SDG thông qua ba loại cạnh mới.

1 Cạnh gọi là các cạnh phụ thuộc điều khiển giữa đỉnh gọi trong đỉnh gọi và đỉnh vào thủ tục tương ứng trong đồ thị phụ thuộc thủ tục

2 Cạnh tham số trong giữa các đỉnh hình thức trong tại thủ tục đƣợc gọi và đỉnh thực trong tại đỉnh gọi

3 Cạnh tham số ngoài giữa các đỉnh hình thức ngoài tại thủ tục đƣợc gọi và đỉnh thực ngoài tại đỉnh gọi

CÁC KỸ THUẬT DÙNG TRONG PHƯƠNG PHÁP DYNAMIC

Phương thức dynamic chương trình đơn thủ tục

3.1.1 : Các khái niệm luồng động

Trong phương pháp dynamic slicing cho chương trình có cấu trúc đơn thủ tục, Korel và Laski mô tả lịch sử thực hiện chương trình như một đường đi chứa chuỗi các sự xuất hiện của câu lệnh và tính chất điều khiển Các nhãn được sử dụng để phân biệt các lần xảy ra khác nhau của một câu lệnh trong lịch sử thực hiện Ví dụ, trong lịch sử thực hiện {1 1, 2 2, 3 3, 4 4, 7 5, 4 6, 8 7}, câu lệnh 4 xuất hiện hai lần tại vị trí thứ 4 và thứ 6.

Hình 14: (a)Đường đi của chương trình mẫu trong Hình 2(a) (b)các khái niệm luồng động cho đường đi đó

Ví dụ 3.1.1.1: Hình 14 thể hiện đường đi của chương trình trong Hình 2(a) với đầu vào n = 2 Đường đi của lịch sử thực hiện của chương trình là{1 1 , 2 2 , 3 3 , 4 4 ,

Dynamic slicing trong kỹ thuật slicing được định nghĩa bởi bộ ba (x, Iq, V), trong đó x là đầu vào chương trình, Iq là câu lệnh thứ q trong lịch sử thực hiện, và V là tập con các biến trong chương trình Để một slice dynamic slicing hợp lệ, nó phải đáp ứng hai yêu cầu: (i) câu lệnh tương ứng với tiêu chuẩn Iq phải có mặt trong slice, và (ii) nếu có vòng lặp trong slice, nó phải được thực hiện đúng số lần như trong chương trình gốc.

Korel và Laski giới thiệu ba khái niệm luồng động hình thức hóa sự phụ thuộc giữa các lần xảy ra của các câu lệnh trong đường đi:

1 Quan hệ định nghĩa, sử dụng (DU): là một liên kết sử dụng của một biến với định nghĩa cuối cùng của nó

2 Quan hệ kiểm tra, điều khiển (TC):là liên kết giữa sự xuất hiện của tính chất điều khiển và câu lệnh, xảy ra trên đường đi phụ thuộc điều khiển vào nó, quan hệ này chỉ có trong kiểu hướng cú pháp chỉ xây dựng cho chương trình có cấu trúc

3 Quan hệ định danh (IR): là liên kết giữa sự xuất hiện khác nhau của cùng một câu lệnh

Ví dụ 3.1.1.2: Hình 14(b) chỉ ra các khái niệm luồng dynamic cho đường đi trong Hình 14(a)

Các slice dynamic slicing được xác định bằng cách liên tục tính toán tập S i của các câu lệnh liên quan trực tiếp và gián tiếp Theo tiêu chuẩn (x, I q , V), phép tính khởi tạo S 0 bao gồm định nghĩa cuối cùng của các biến trong V trên đường đi và kiểm tra các hành động mà tại đó I q phụ thuộc vào điều khiển Tính toán S i+1 được xác định dựa trên quy trình này.

Slice dynamic slicing thu đƣợc dễ dàng từ tập cố định S C của quá trình trên

Slice slicing gồm tất cả các câu lệnh X mà có thể thực hiện X p xuất hiện trong S C và câu lệnh i tương ứng với tiêu chuẩn I q

Trong ví dụ 3.1.1.3, chúng ta thực hiện dynamic slicing cho đường đi trong Hình 14 với tiêu chuẩn (n = 2, 8 12 , {x}) Ban đầu, tập S0 chứa định nghĩa cuối cùng của x, cụ thể là S0 = {5 9} Tiếp theo, chúng ta tính toán được A1 = {3 7 , 4 8}, A2 = {7 6 , 1 1 , 3 3 , 3 11 , 4 4} và A3 = {2 7}.

7 10 } Từ đó theo quá trình trên ta tính đƣợc:

Slice dynamic slicing với tiêu chuẩn (n= 2, 8, 12, {x}) bao gồm tất cả các câu lệnh của chương trình, ngoại trừ câu 5, tương ứng với câu 6 trong đường đi Hình 2(b) minh họa slice slicing của chương trình này.

Hình 15 mô tả đường đi của chương trình mẫu với đầu vào n=1, đồng thời giới thiệu các khái niệm luồng động liên quan đến đường đi này Ngoài ra, hình ảnh cũng thể hiện kỹ thuật cắt động (dynamic slicing) với tiêu chuẩn n=1, 8 8, x Cuối cùng, cắt slicing không dừng sẽ thu được kết quả nếu bỏ qua các mối quan hệ.

Vai trò của quan hệ định danh IR là duyệt chương trình theo cả hai hướng, đồng thời đưa vào tất cả các câu lệnh và tính chất điều khiển cần thiết để đảm bảo việc kết thúc các vòng lặp trong quá trình slice slicing.

Ví dụ 3.1.1.4: Chúng ta xem xét vai trò của quan hệ định danh IR Xét đường đi của chương trình mẫu trong Hình 2(a) với đầu vào n = 1 thể hiện trong

Hình 15(a) minh họa các khái niệm luồng dynamic với đường đi và slice slicing theo tiêu chuẩn (n=1, 8 8, {x}) Hình 15(b) và 15(c) thể hiện slice slicing thu được là một chương trình kết thúc Tuy nhiên, khi tính các slice slicing mà không sử dụng quan hệ định danh IR, ta sẽ thu được một chương trình không kết thúc, như thể hiện trong Hình 15(d) Hiện tượng này xảy ra do quan hệ DU và TC chỉ duyệt đường đi theo hướng ngược lại.

Hình 16: (a) Chương trình mẫu (b)Đường đi với đầu vào n = 2

Tuy nhiên duyệt quan hệ IR theo hướng ngược lại làm cho slice slicing chứa các câu lệnh không cần thiết để đảm bảo sự kết thúc

Hình 16(a) trình bày phiên bản sửa đổi của chương trình trong Hình 2(a), trong khi Hình 16(b) thể hiện đường đi của chương trình Từ đường đi này, ta xác định được các phụ thuộc như (7 6, 7 11) thuộc IR, (6 5, 7 6) thuộc DU và (5 10, 7 11) thuộc TC Kết quả là cả câu lệnh 5 và 6 đều có trong slice slicing, mặc dù câu lệnh 6 không cần thiết để tính giá trị cuối cùng của z hay để kết thúc vòng lặp.

Agrawal và Horgan đã phát triển một phương pháp sử dụng đồ thị phụ thuộc để thực hiện tính toán slice dynamic slicing Mặc dù thuật toán đầu tiên của họ không đạt độ chính xác cao trong việc tính toán slice dynamic slicing, nhưng nó vẫn rất hữu ích để làm nền tảng cho việc hiểu các thuật toán phát triển sau này.

Hướng tiếp cận đầu tiên sử dụng đồ thị PDG để đánh dấu các đỉnh là “đã thực hiện” cho tập các đỉnh được đưa ra Một slice dynamic slicing được tính toán thông qua việc thực hiện một slice static slicing cho đồ thị con chỉ gồm các đỉnh được đánh dấu của PDG Tuy nhiên, giải pháp này không hoàn toàn chính xác vì nó không xem xét các cạnh luồng trong PDG giữa hai đỉnh được đánh dấu v1 và v2, trong khi định nghĩa của v1 không được sử dụng tại v2 Hơn nữa, khi một đỉnh được đánh dấu xuất hiện trong nhiều vòng lặp, nó sẽ được biểu diễn trong tất cả các vòng lặp tiếp theo, ngay cả khi các sự phụ thuộc không được lặp lại.

Ví dụ 3.1.2.1: Hình 18(a) chỉ ra đồ thì PDG của chương trình mẫu ở Hình

Để tính toán một slice dynamic slicing với giá trị cuối cùng của x khi đầu vào n = 2, tất cả các đỉnh của PDG đều được thực hiện và đánh dấu Thuật toán static slicing ở phần 2.1.2 cho thấy slice dynamic slicing bao gồm toàn bộ chương trình mẫu Tuy nhiên, câu lệnh gán x := 18 không có liên quan trong ngữ cảnh này Mặc dù phép gán này được đưa vào slice do có sự phụ thuộc từ đỉnh x = 18 đến đỉnh write(x), nhưng nó không biểu diễn sự phụ thuộc trong vòng lặp thứ hai Sự phụ thuộc này chỉ xảy ra khi biến điều khiển i có giá trị lẻ trong vòng lặp.

Giải pháp thứ hai dựa trên đồ thị PDG với các đỉnh phân biệt tương ứng với mỗi lần xuất hiện của câu lệnh trong đường đi, được gọi là đồ thị phụ thuộc động (DDG) Một tiêu chuẩn dynamic slicing được xác định tại một đỉnh trong DDG, và slice dynamic slicing được tính bằng cách lấy tất cả các đỉnh DDG có thể đi tới từ đỉnh tiêu chuẩn Một câu lệnh hoặc tính chất điều khiển nằm trong slice slicing nếu tiêu chuẩn được xem xét từ ít nhất một đỉnh trong sự xuất hiện của nó.

Nhƣợc điểm của đồ thị PDG là số đỉnh bằng số câu lệnh thực thi không bị ràng buộc

Hình 18(c) minh họa đồ thị DDG cho chương trình mẫu ở Hình 16(a), với tiêu chuẩn slicing tương ứng tại đỉnh có nhãn write(z) Tất cả các đỉnh từ đỉnh này được in đậm cho thấy khả năng truy cập Tuy nhiên, tiêu chuẩn không được xem xét từ đỉnh có nhãn x; = 18, do đó câu lệnh gán tương ứng không có trong slice slicing.

Hình 17: Chương trình Q n có O(2 n ) slice dynamic slicing khác nhau

Trong giải pháp thứ ba, Agarwal và Horgan đề xuất cách giảm số đỉnh trong

Dynamic slicing đa thủ tục

Agrawal, Demillo và Spafford đã nghiên cứu phương pháp dynamic slicing đa thủ tục với các cơ chế truyền tham số khác nhau Trong nghiên cứu này, họ xem xét một thủ tục P với các tham số hình thức f1, …, fn được gọi bởi các tham số thực a1, …, an Điểm đáng chú ý trong cách tiếp cận này là việc xác định phụ thuộc dữ liệu động dựa trên định nghĩa và sử dụng vùng nhớ Phương pháp này giúp tránh hai vấn đề chính: (i) việc sử dụng biến toàn cục trong các thủ tục không gây ra lỗi, và (ii) không cần phân tích các bí danh.

Tham số truyền tham trị được thiết lập thông qua chuỗi lệnh gán f1 := a1, , fn := an trước khi vào thủ tục Để xác định các ô nhớ cho việc ghi hành động chính xác, tập USE cho các tham số thực ai được xác định trước khi vào thủ tục, trong khi tập DEF cho các tham số hình thức fi được xác định sau khi vào thủ tục Đối với tham số truyền tham trị kết quả, các phép gán từ tham số hình thức đến tham số thực cần được thực hiện khi rời khỏi thủ tục Trong khi đó, tham số truyền tham chiếu không yêu cầu các chi tiết hành động đến slice dynamic slicing, mà chỉ cần liên kết giữa các ô nhớ tương ứng giữa tham số thực và tham số hình thức ai và fi.

Một hướng tiếp cận khác của dynamic slicing đa thủ tục được giới thiệu bởi

Kamkar, Shahmehri và Fritzson nghiên cứu các tập hợp đỉnh trong chương trình ảnh hưởng đến giá trị của một biến tại một đỉnh cụ thể Họ đã xây dựng một đồ thị tổng hợp phụ thuộc động (DDSG), trong đó các đỉnh biểu thị các thể hiện thủ tục tương ứng với sự kích hoạt thủ tục, được chú thích bằng các tham số Các cạnh của đồ thị tổng hợp thể hiện các lời gọi thủ tục và các cạnh phụ thuộc tổng hợp.

Tiêu chuẩn slicing được xác định qua một cặp bao gồm một thể hiện thủ tục và một tham số ra hoặc vào của thủ tục liên kết Sau khi xây dựng đồ thị tổng hợp, quá trình xác định một slice slicing theo tiêu chuẩn slicing diễn ra qua hai bước Đầu tiên, các phần của đồ thị tổng hợp dẫn đến đỉnh tiêu chuẩn được xác định, từ đó tạo ra đồ thị con, gọi là slice slicing thực thi Các đỉnh của slice slicing thực thi đại diện cho một thể hiện thủ tục cụ thể, trong đó các tham số có thể bị loại bỏ Một slice slicing trong chương trình đa thủ tục bao gồm tất cả các đỉnh gọi trong chương trình mà có một thể hiện cụ thể xuất hiện trong slicing thực thi.

Có ba phương pháp để xây dựng một đồ thị tổng hợp Phương pháp đầu tiên xác định các phụ thuộc dữ liệu đơn thủ tục một cách tĩnh, dẫn đến việc tạo ra slice slicing không chính xác khi có các câu lệnh điều kiện Phương pháp thứ hai xác định tất cả các phụ thuộc tại thời điểm thực thi, yêu cầu tính toán các phụ thuộc của thủ tục P mỗi khi P được gọi để đảm bảo slice slicing chính xác Cuối cùng, phương pháp thứ ba kết hợp hiệu quả của phương pháp tĩnh với độ chính xác của phương pháp động bằng cách tính toán các phụ thuộc trong các khối cơ bản tĩnh và các phụ thuộc động giữa các khối Trong tất cả các phương pháp này, các phụ thuộc điều khiển được xác định theo cách tĩnh.

THỰC NGHIỆM TRÊN CÁC CHƯƠNG TRÌNH SLICER

Chương trình StaticSlicer

Bài toán cho chương trình như sau:

Xét tiêu chuẩn slicing (n, {v}) = (19, {z}) n = 19 là vị trí của câu lệnh, v = z là biến của câu lệnh n

Ngày đăng: 16/11/2023, 07:35

Nguồn tham khảo

Tài liệu tham khảo Loại Chi tiết
[3] K.J. Ottenstein and L.M. Ottenstein. The program dependence graph in a software development environment. In Proceedings of the ACM SIGSOFT/SIGPLANSoftware Engineering Symposium on Practical Software Development Environments Khác
[4] J.-F. Bergeretti and B.A. Carre. Information- ow and data- ow analysis of while programs. ACM Transactions on Programming Languages and Systems Khác
[5] B. Korel and J. Laski. Dynamic slicing of computer programs. Journal of Systems and Software Khác
[6] S. Horwitz and T. Reps. The use of program dependence graphs in software engineering. In Proceedings of the14th International Conference on Software Engineering Khác
[7] S. Horwitz, T. Reps, and D. Binkley. Interprocedural slicing using dependence graphs. ACM Transactions on Programming Languages and Systems Khác
[8] H. Agrawal and J.R. Horgan. Dynamic program slicing. In Proceedings of the ACM SIGPLAN’90 Conference on Programming Language Design and Implementation Khác
[9] H. Agrawal, R.A. DeMillo, and E.H. Spafford. Dynamic slicing in the presence of unconstrained pointers. In Proceedings of the ACM Fourth Symposium on Testing, Analysis, and Verification (TAV4) Khác

TÀI LIỆU CÙNG NGƯỜI DÙNG

  • Đang cập nhật ...

TÀI LIỆU LIÊN QUAN

w