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

Phân tích source code và các giải pháp nâng cao kỹ thuật viết mã loại bỏ lỗi lập trình và tăng hiệu quả của chương trình

89 54 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

Định dạng
Số trang 89
Dung lượng 0,99 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Phân tích source code và các giải pháp nâng cao kỹ thuật viết mã loại bỏ lỗi lập trình và tăng hiệu quả của chương trình Phân tích source code và các giải pháp nâng cao kỹ thuật viết mã loại bỏ lỗi lập trình và tăng hiệu quả của chương trình luận văn tốt nghiệp thạc sĩ

Trang 1

NGUYỄN THỊ THANH NGA

PHÂN TÍCH SOURCE CODE VÀ CÁC GIẢI PHÁP NÂNG CAO

KỸ THUẬT VIẾT MÃ LOẠI BỎ LỖI LẬP TRÌNH VÀ TĂNG

HIỆU QUẢ CỦA CHƯƠNG TRÌNH

Chuyên ngành: CÔNG NGHỆ THÔNG TIN

Trang 2

Cán bộ hướng dẫn khoa học : PGS.TS.Huỳnh Quyết Thắng

Cán bộ chấm nhận xét 1 :

Cán bộ chấm nhận xét 2 :

Luận văn thạc sĩ được bảo vệ tại

HỘI ĐỒNG CHẤM BẢO VỆ LUẬN VĂN THẠC SĨ

TRƯỜNG ĐẠI HỌC BÁCH KHOA HÀ NỘI, ngày tháng năm 2009

Trang 3

LỜI CẢM ƠN

Tôi xin gởi lời cảm ơn chân thành nhất đến PGS TS Huỳnh Quyết Thắng, người đã tận tình hướng dẫn, giúp đỡ tôi trong suốt quá trình thực hiện luận văn và tạo điều kiện để tôi có thể hoàn thành luận văn này

Xin gởi lời cản ơn đến các Thầy Cô đã dạy tôi trong thời gian qua Tôi xin cảm ơn các bạn đồng môn và đồng nghiệp đã quan tâm, chia sẽ trong suốt quá trình học và làm luận văn

Xin cảm ơn gia đình đã dành cho tôi tình thương yêu và sự hỗ trợ tốt nhất

Trang 4

MỤC LỤC

Chương 1 TỔNG QUAN 9

1.1 Giới thiệu 9

1.2 Sơ lược về phân tích mã nguồn 9

1.3 Mục đích nghiên cứu đề tài 11

Chương 2 CƠ SỞ LÝ THUYẾT 12

2.1 Abstract Syntax Tree (AST) 12

2.2 Phân tích mã nguồn 18

2.3 Vấn đề tìm lỗi 18

2.3.1 Các loại phân tích mã nguồn 20

2.3.2 Các bước thực hiện phân tích mã nguồn 21

2.3.3 Xử lý phân tích: 23

Chương 3 ĐO LƯỜNG CHẤT LƯỢNG THIẾT KẾ 26

3.1 Làm thế nào để đo lường chất lượng của thiết kế 26

3.2 Các thông số đánh giá chất lượng thiết kế: 26

3.3 Hiện thực 31

Chương 4 PHÁT HIỆN VÀ KHẮC PHỤC LỖI TRONG PHÁT TRIỂN CHƯƠNG TRÌNH 35

4.1 Làm thế nào để phát hiện lỗi và khắc phục .35

4.2 Thực hiện 37

4.3 Phương pháp nhận dạng những lỗi bảo mật của chương trình 40

4.4 SQL Injection 41

4.5 Cross-site scripting 42

4.6 Các khắc phục lỗi bảo mật 43

4.6.1 SQL Injection 43

4.6.2 Cross-site scripting 45

Chương 5 ĐO LƯỜNG HIỆU QUẢ PHẦN MỀM 47

5.1 Phân tích dựa trên thành phần (Component Base Software Engineering) 47

5.2 Thuật ngữ và khái niệm 47

5.3 Motivation 49

5.4 Mô hình Component 50

5.5 Dự đoán hiệu quả trong CBSE 51

5.5.1 Nhân tố ảnh hưởng hiệu quả 52

Trang 5

5.5.2 Phương pháp dự đoán hiệu quả 53

5.6 Mô hình thành phần song song 57

5.6.1 Xử lý phát triển 57

5.6.2 Các thành phần PCM 59

5.7 Phân tích mã nguồn phục vụ việc đo lường tốc độ thực thi 62

5.7.1 Các thuộc tính mong muốn của RDSEFFs 63

5.7.2 Sử dụng tài nguyên 64

5.7.3 Các thành phần đáp ứng cần thiết 67

5.7.4 Nhiệm vụ của chuyển đổi code sang RDSEFFs 68

5.8 Xây dụng RDSEFFs từ code Java 73

Chương 6 TRIỂN KHAI THỬ NGHIỆM VÀ ĐÁNH GIÁ TRÊN ỨNG DỤNG THỰC TẾ 79 6.1 Đo lường chất lượng thiết kế (Design) 79

6.2 Đo lường chất lượng và bảo mật cho sản phẩm (Quality & Security) 81

Chương 7 KẾT LUẬN VÀ KIẾN NGHỊ 85

DANH MỤC TÀI LIỆU THAM KHẢO 86

Trang 6

DANH MỤC HÌNH

Hình 3.1-1: Ví dụ kết quả cây phân tích 12

Hình 3.3-1: Vai trò của phân tích tĩnh trong xử lý phát triển phần mềm 19 Hình 3.3-2: Tìm lỗi trong dự án phát triển phần mềm sử dụng công cụ phân tích tĩnh 22

Hình 4.2-1: Các class bên ngoài phụ thuộc vào class bên trong package 27

Hình 4.2-2: Class bên trong package phụ thuộc vào các class bên ngoài 27

Hình 4.2-3: Độ ổn định của package 29

Hình 4.2-4: Độ ổn định và abstract class 30

Hình 4.2-5: Một ví dụ cho các tham số của package 33

Hình 4.2-6: Phân tích dựa vào các tham số của package 33

Hình 5.2-1: Cây AST cho một đoạn code ví dụ 1 38

Hình 5.2-2: Cây AST cho phân tích một đoạn code ví dụ 2 40

Hình 5.6-1: Cây AST cho phân tích một đoạn code ví dụ 3 45

Hình 6.1-2 : Kết quả phân tích mã nguồn 80

Hình 6.1-2 : Tổng hợp kết quả phân tích 81

Hình 6.2.1: Bảng tổng kết lỗi tìm thấy 82

Hình 6.2.2 : Bảng chi tiết các lỗi được phân loại 82

Trang 7

MỞ ĐẦU

Sự gia tăng đáng kể số lượng phần mềm được sử dụng hàng năm đòi hỏi nhu cầu phát triển của người lập trình và sản phẩm lập trình Nhưng việc thuê người lập trình thì tốn kém và không hiệu quả nếu như hệ thống xem xét là quá lớn và không thể chia thành nhiều phần nhỏ Sự phức tạp của phần mềm hiện đại đòi hỏi có giải pháp để đứng vững đó là sử dụng công cụ hỗ trợ Chuộng nhất là các công cụ dựa vào việc phân tích mã nguồn, như các công cụ cung cấp thông tin cho người lập trình để tăng hiệu quả công việc và cải tiến toàn diện sản phẩm của người lập trình

Với thực tế như vậy, nên việc tìm hiểu về Phân tích Mã nguồn và các giải pháp nâng cao kỹ thuật viết mã (Code Optimization Secure Coding) loại

bỏ lỗi lập trình và tăng hiệu quả của chương trình là một chủ đề không thể thiếu cho các lập trình viên, cho các kỹ sư phần mềm và cho những ai muốn nâng cao khả năng viết code của mình

 Công nghệ cho việc đánh giá và hiện thực

Ngôn ngữ Java

Hệ điều hành Windows

 Kết cấu của luận văn

Luận văn bao gồm 7 chương

Trang 8

Chương này trình bày các khái niệm cơ bản, các cơ sở lý thuyết cho việc phân tích mã nguồn.

Chương 3 Đo lường chất lượng thiết kế

Chương này trình bày phương pháp phân tích đo lường chất lượng thiết kế

Chương 4 Phát hiện và khắc phục lỗi

Chương này trình bày phương pháp phân tích phát hiện và khắc phục lỗi

Chương 5 Đo lường hiệu quả phần mềm

Chương này trình bày phương pháp phân tích đo lường hiệu quả phần mềm

Chương 6 Triển khai thử nghiệm và đánh giá trên ứng dụng thực tế

Trên cơ sở lý thuyết đã trình bày chương này triển khai trong ứng dụng thực tế đo lường chất lượng thiết kế, tìm và sửa lỗi, bảo mật chương trình

Chương 7 Kết luận và kiến nghị

Chương này trình bày các kết quả đạt được của bài toán, đề cập lạinhững việc đã thực hiện được của đề tài Nêu lên hướng mở rộng và phát triển tiếp theo cho đề tài

Trang 9

Chương 1 TỔNG QUAN

1.1 Giới thiệu

Phân tích mã nguồn (mã nguồn) tự động và bán tự động vẫn là chủ

đề nghiên cứu lớn trong nhiều năm qua Trong suốt giai đoạn này, kỹ thuật

và giải thuật phân tích mã nguồn đã thay đổi khá lớn, đôi khi thay đổi đột ngột Khả năng của các công cụ hiện thực phân tích mã nguồn cũng mở rộng để đáp ứng với những thách thức và thay đổi mới đó Trong đề tài này

ta bàn về phân tích mã nguồn Đề tài cũng cung cấp định hướng cho công việc tương lai trong giai đoạn năm năm tới và nghiên cứu sự phát triển của các ứng dụng, kỹ thuật, và thách thức trong phân tích mã nguồn trong 10,

20 và 50 năm tới

Với cái nhìn như vậy, phân tích mã nguồn có mục đích là đạt đến một kết quả nào đó Việc xác định kết quả mong muốn là hết sức quan trọng Kết quả mong muốn phải được định nghĩa đầu tiên Sau đó lựa chọn các kỹ thuật phân tích mã nguồn được áp dụng để đạt đến kết quả này

1.2 Sơ lược về phân tích mã nguồn

Phân tích mã nguồn là việc kiểm tra code tự động với mục đích tìm lỗi của chương trình hoặc ứng dụng trước khi đưa cho người sử dụng Mã nguồn bao gồm các câu lệnh tạo bằng chương trình soạn thảo hoặc bằng công cụ lập trình và sau đó lưu trong một file [tài liệu trích dẫn]

Phân tích mã nguồn có thể là tĩnh hoặc động [tài liệu trích dẫn]

a Phân tích tĩnh

Là việc tìm lỗi bằng cách kiểm tra code mà không cần thực thi chương trình Nên có thể phát hiện được lỗi trong giai đoạn đầu khi phát triển chương trình, thường loại trừ được rất nhiều lỗi cần thiết cho nhiều phiên bản sau đó

Trang 10

Trong hầu hết trường hợp phân tích được thực hiện trên một số phiên bản của mã nguồn và một số trường hợp khác của object code Thuật ngữ thường được cung cấp để thực hiện phân tích bởi một công cụ tự động, với việc phân tích của người gọi chương trình hoặc hiểu chương trình.

Sự tinh tế của việc phân tích thực hiện bởi công cụ là khác nhau từ việc xem xét hành xử của các câu lệnh và khai báo độc lập, điều này bao gồm hoàn thành mã nguồn của chương trình họ phân tích

Phân tích tĩnh không có bản miêu tả cho chương trình đầu vào vì vậy kết quả phải được cung cấp đến tất cả chương trình thực thi Sự đánh giá xấp xỉ bắt buộc phải làm Trái lại, phân tích động bắt chương trình đầu vào phải có bản miêu tả ( tiêu biểu là đầu vào đơn) Điều này cho phép chính xác hơn, tuy nhiên, kết quả chỉ là sự bảo đảm đúng cho đầu vào cụ thể

b Phân tích động

Sau khi phân tích tĩnh, phân tích động được thực hiện để phát hiện nhiều lỗi khó thấy hoặc các lỗi bảo mật Phân tích kiểm tra chương trình thời gian thực

Phân tích động thường sử dụng file lưu vết Đơn giản là ghi lại toàn

bộ đường đi để đưa đến không gian có thể xem xét Ball và Larus mô tả một giải thuật để chỉ dẫn chương trình giới thiệu trên đầu nhỏ nhất Mục tiêu của họ chụp lại lịch sử thực thi và vì vậy luồng điều khiển động của chương trình trong khi nén vết Hệ thống khác chụp trạng thái của việc tính toán các chi tiết mẫu có thể là trễ sử dụng kỹ thuật phân tích thống kê

Ưu điểm chính của phương pháp này :

 Không yêu cầu người lập trình có khả năng dự đoán tình huống để xảy

ra lỗi

Trang 11

 Loại trừ sự không cần thiết component chương trình và đảm bảo chương trình kiểm tra là tương thích với chương trình khác như việc chạy đồng thời.

1.3 Mục đích nghiên cứu đề tài

Phân tích mã nguồn nhằm:

 Xác định độ phức tạp của ứng dụng, chất lượng của thiết kế (Design)

 Dự đoán lỗi xãy ra trong thời gian thực thi để có cách khắc phục (Quality)

 Phân tích mã nguồn nhằm xác định các lỗi lập trình làm giảm tốc độ thực thi của ứng dụng (Performance)

 Phân tích mã nguồn để tìm ra những lỗi bảo mật của sản phẩm mà là nguyên nhân giúp hacker khai thác và tấn công để lấy cắp dữ liêu, hoặc phá hủy dữ liệu

Kết chương

Phân tích mã nguồn là một hướng phát triển không thể thiếu trong công nghệ phát triển chương trình Giúp nhà lập trình xây dựng các công cụ tiện ích trong quá trình xây dựng và phát triển sản phẩm Chương 1 đã trình bày tổng quan về phân tích mã nguồn, phân tích mã nguồn tĩnh và động, cũng như trình bày mục đích của việc phân tích mã nguồn

Trang 12

Chương 2 CƠ SỞ LÝ THUYẾT2.1 Abstract Syntax Tree (AST)

Cây AST xây dựng cấu trúc đặc tả của dữ liệu nhập dưới dạng cây Cây AST khác với cây cú pháp bình thường bởi việc bỏ đi các nút chứa dấu kết thúc câu lệnh hoặc dấu “,” phân biệt các tham số trong function

AST có thể được tạo với parser viết bằng tay hoặc code đưa ra bởi

bộ tạo parser AST được tạo từ dưới lên

Khi thiết kế các nút của cây, thiết kế thường lựa chọn xác định biểu diễn của cây AST Có nghĩa là, tất cả construct của ngôn ngữ source được biểu diễn như các kiểu khác nhau của các nút AST hoặc một số construct của ngôn ngữ source được biểu diễn với kiểu thông thường của nút AST và một số khác sử dụng giá trị

Ví dụ: phân tích hai biểu thức 1 + 2 * 3 + 4 * 5 và 1 +2 * (3 + 4) * 5 tương ứng trong hình 1 trái và phải

Hình 3.1-1: Ví dụ kết quả cây phân tíchTrong hình có thể thấy, biểu thức có thể được trở về dạng ban đầu của nó bằng cách duyệt cây từ trái sang phải

Sau khi cây AST được tạo và xác định, bộ phân tích cú pháp sẽ kiểm tra

Trang 13

Các công cụ lấy source Java như đầu vào bằng cách scan source Java sử dụng parsers, sau đó thực hiện định nghĩa trước các rule trên mã nguồn Việc hiểu rõ ngôn ngữ cho bất kỳ công cụ nào có thể xác định được lỗi trong một ngôn ngữ lập trình cụ thể Cho Java có nhiều parsers có thể như JavaCC (https://javacc.dev.java.net/) and ANTLR (http://www.antlr.org/)

Java parser là công cụ đơn giản như source Java bằng cách chuyển

mã nguồn vào cấu trúc cây Có nhiều Java parser đơn giản code thành cấu trúc cây (Abstract Syntax Tree)

public class GenerateAST {

private String printFuncName() {

System.out.println(funcName + "Generate AST");

Trang 15

Ta sử dụng JavaCC và the JJTree parser (https://javacc.dev.java.net/) để xây dựng chương trình nhận dạng trùng với ngữ pháp đặc tả Ngoài ra, nó cũng tạo một cây AST của file Java source

Ta sử dụng qui luật thiết kế PMD (http://pmd.sourceforge.net/) để trình bày việc tạo cây AST bởi JavaCC và JJTree từ Java source Parser và cấu trúc code sẽ giúp công cụ cài đặt đảm nhiệm vai trò không chỉ về phát hiện lỗi cú pháp mà còn về phân tích lỗi luồng dữ liệu

Tạo cây AST được scan bởi việc định nghĩa các mẫu cung cấp trong rule sử dụng bộ tạo parser AST API Ta minh họa kỹ thuật này bằng việc cài đặt rule để bắt lấy các lỗi thông dụng và các lỗi performance, với developer không có kinh nghiệm bằng cách cắt chuỗi trong vòng

lặp thay cho việc sử dụng stringbuffer StringConcatInForRule class

trình bày cài đặt rule này

public class StringConcatInForRule {

static int lineNo = 0;

Trang 16

public Object visitRule(ASTForStatement node, Object data) {

ASTMethodDeclaration method = (ASTMethodDeclaration) node .getFirstParentOfType(ASTMethodDeclaration.class);

List localvars = new ArrayList();

if (method != null) {

method.findChildrenOfType(ASTLocalVariableDeclaration.class, localvars, true);

for (Iterator lvars = localvars.iterator(); lvars.hasNext();) {

ASTLocalVariableDeclaration localvar =

(ASTLocalVariableDeclaration) lvars.next();

if (localvar.jjtGetChild(0).jjtGetChild(0)

instanceof ASTName) {

ASTName localVarName = (ASTName) localvar.jjtGetChild(0) .jjtGetChild(0);

if (localVarName.getImage().equals("String")) {

if (localvar.jjtGetChild(1)

instanceof ASTVariableDeclarator) {

ASTVariableDeclaratorId varId =

(ASTVariableDeclaratorId) localvar

jjtGetChild(1).jjtGetChild(0);

checkForConcat(node, varId.getImage(), data);

}

}

}

}

}

return data; }

Trang 17

public boolean checkForConcat(ASTForStatement node, String varName, Object data) {

boolean closed = false;

List blocks = new ArrayList();

int oldLineNo = 0;

node.findChildrenOfType(ASTBlockStatement.class, blocks, true); for (Iterator it2 = blocks.iterator(); it2.hasNext();) {

ASTBlockStatement block = (ASTBlockStatement) it2.next();

List exps = new ArrayList();

block.findChildrenOfType(ASTExpression.class, exps, true);

for (Iterator it = exps.iterator(); it.hasNext();) {

ASTExpression exp = (ASTExpression) it.next();

if (exp.jjtGetChild(0) instanceof ASTAdditiveExpression) {

List names = new ArrayList();

exp.findChildrenOfType(ASTName.class, names, true);

for (Iterator it1 = names.iterator(); it1.hasNext();) {

ASTName name = (ASTName) it1.next();

Trang 18

 Biểu diễn bên trong: trừu tượng hành vi cụ thể của chương trình thành dạng phù hợp hơn với phân tích cú pháp Biểu diễn bên trong được giới thiệu trực tiếp bởi bộ phân tích cú pháp( ví dụ đồ thị luồng điều khiển), trong khi cái khác yêu cầu kết quả của phân tích được ưu tiên ( ví dụ, đồ thị phụ thuộc yêu cầu điểm trước để phân tích).

 Phân tích (analys) Phân tích có thể được phân loại theo 6 đại lượng : tĩnh hay động, có âm hay không có âm, an toàn hay không an toàn, nhạy phân luồng hay không nhạy phân luồng, nhạy ngữ cảnh hay không nhạy ngữ cảnh và sự phức tạp

2.3 Vấn đề tìm lỗi

Tìm lỗi trong phần mềm thường thì được làm bằng cách review code, unit testing, system testing, integration testing và user-acceptance testing Giai đoạn đầu tiên có thể tìm lỗi là review code, sẽ giúp tìm ra lỗi sớm bằng

Trang 19

cách đặc tả cú pháp của ngôn ngữ lập trình được sử dụng Quá trình này

sẽ làm giảm xác suất lỗi Công việc này có thể làm bằng tay Tuy nhiên việc

xử lý có thể trở nên cồng kềnh và khó quản lý đối với người lập trình đặc biệt khi được đảm nhiệm tại đoạn cuối của quá trình xây dựng, vì lúc này code nhiều Nói tóm lại, việc review code bằng tay cho một dự án lớn thì hoặc không hiệu quả hoặc không thể thực hiện được, cũng như yêu cẩu nổ lực cho review code bằng tay là quá lớn

Phân tích tĩnh cung cấp cơ chế cho việc review code tự động bằng công cụ để sớm tìm thấy lỗi trong quá trình xây dựng Phân tích tĩnh là giai đoạn sớm nhất không chỉ loại bỏ lỗi mà còn giúp xác định được lỗi trước khi chạy chương trình Phân tích tĩnh đảm bảo xác định lỗi sớm và sửa lỗi bằng cách so sánh mã nguồn với ngôn ngữ định nghĩa trước, cải tiến sự phát triển sản phẩm và độ tin cậy của sản phẩm đầu ra Phân tích tĩnh cũng giúp cho việc viết code phải theo chuẩn, vì vậy việc bảo trì được dễ dàng hơn

Một dự án lớn sẽ phải tốn hơn phân nữa thời gian trong việc tìm lỗi

và ngăn chặn lỗi Ta có thể giảm thời gian này bằng cách xử lý review code một cách tự động Việc tự động cũng giúp chuẩn hóa code mang lại hiệu quả trong làm việc nhóm và cho tổ chức

Hình 3.3-1: Vai trò của phân tích tĩnh trong xử lý phát triển phần mềm

Trang 20

Đây là hình minh họa vai trò của phân tích tĩnh trong chu kỳ phát triển phần mềm.

Cụ thể:

Developer: viết code và thực hiện phân tích tĩnh để xác định lỗi và sửa lỗi

Architect: lựa chọn công cụ phân tích tĩnh và cấu hình các rule

Software Quality Advisor: phân tích lỗi và ngăn chặn lỗi

Scanning Java Source:

2.3.1 Các loại phân tích mã nguồn

 Phân tích cú pháp: được làm bởi việc xác định cấu trúc của code Java đầu vào và so sánh chúng với các mẫu được định nghĩa trước Thông thường việc tìm lỗi sử dụng phương pháp này đang là qui ước như là tên chuẩn hoặc thường là nguyên lý mặc định

Trang 21

đoán các tình huống xảy ra như biểu thức con trỏ null hoạc đối tượng dữ liệu chưa đóng trong tất cả các luồng có thể có

class TestResourceLeak

{

ResourceException {

CoreResponse coreresponse = new CoreResponse();

DatabaseConnection dbcon = new DatabaseConnection();

Connection con1 = null;

Connection con2 = null;

//getting the Data Base Connection

Trang 22

Hình 3.3-2: Tìm lỗi trong dự án phát triển phần mềm sử dụng công cụ

phân tích tĩnhPhân tích tĩnh cho phép kiểm tra code chương trình trước khi kiểm tra chương trình thực thi Phân tích tĩnh bao gồm 3 bước:

 Phân tích code chương trình thành các token như: hằng số, định danh, ký hiệu,…Công việc này được thực hiện bởi lexer

 Các token được được chuyển qua parser, xây dựng một cây AST dựa trên các token

 Phân tích tĩnh được thực hiện qua cây AST

Kiểm tra ứng dụng là một phần quan trọng của xử lý phát triển phần mềm Có nhiều loại khác nhau của kiểm tra phần mềm Trong số đó có

2 loại code của ứng dụng: phân tích tĩnh và phân tích động

Phân tích động được thực hiện dựa vào code thực thi của chương trình biên dịch Phân tích động chỉ kiểm tra hành vi đặc tả của user Có nghĩa là chỉ code, thực thi trong suốt quá trình test được kiểm tra Phân tích

Trang 23

động có thể cung cấp cho người lập trình thông tin về thiếu bộ nhớ, performance của chương trình, gọi stack, …

Phân tích tĩnh cho phép kiểm tra code chương trình trước khi chương trình kiểm tra được thực thi Compiler thường thực hiện phân tích tĩnh trong suốt quá trình xử lý biên dịch Tuy nhiên, chu kỳ sống của dự án thường cần toàn bộ mã nguồn đầy đủ các yêu cầu thêm vào Các yêu cầu thêm này

có thể khác với tên biến ban đầu Các yêu cầu thông thường là:

 Độ tin cậy: chương trình ít lỗi

 Khả năng bảo trì: Người khác có thể hiểu được source để dễ nâng cấp, thay đổi mã nguồn

 Khả năng kiểm tra: ít tốn thời gian kiểm tra vì xử lý kiểm tra có hiệu quả hơn

 Khả năng di chuyển: linh động khi chương trình kiểm tra chạy trên platform phần cứng khác nhau

 Khả năng đọc: Người khác hiểu được code và vì vậy ít tốn thời gian review và đọc code được rõ ràng

Tất cả các yêu cầu có thể được chia ra làm hai loại: qui tắc và hướng dẫn

Qui tắc: mang tính bắt buộc

Hướng dẫn: mang tính đề nghị

Phân tích tĩnh tìm những dòng code không đúng với chuẩn viết code

sẽ hiển thị thông báo để người lập trình có thể hiểu những dòng này sai cái gì

Phân tích tĩnh xử lý giống như bộ biên dịch, chỉ khác là nó không thực thi hoặc không có đối tượng code được tạo

2.3.3 Xử lý phân tích:

Trang 24

Xử lý phân tích tĩnh bao gồm hai bước: tạo cây AST và phân tích cây AST.

Để phân tích code, công cụ phân tích tĩnh phải hiểu được code, phân tích nó và tạo một cấu trúc cây AST

Trường hợp tổng quát, một cây AST được xây dựng chỉ cho một đoạn phân tích của mã nguồn Trước khi cây có thể được xây dựng, trước tiên mã nguồn được xử lý bởi lexer và sau đó bởi parser

Lexer làm nhiệm vụ chia dòng dữ liệu đầu vào thành các token riêng biệt, xác định kiểu của token, và chuyển các token này đến giai đoạn kế của quá trình phân tích

Lexer đọc dữ liệu text từng dòng một và chia các dòng này thành từ, định danh và hằng số, những cái này gọi chung là token Sau đó token được lấy ra, lexer xác định kiểu của token này

Nếu ký tự đầu tiên của token là ký tự số thì token là số, nếu ký tự đầu tiên là dấu trừ thì token là số âm Nếu token là số, nó có thể là số thực hoặc

số nguyên Nếu nó chứa dấu « » hoặc « E » thì nó là số thực ngược lại là

số nguyên

Nếu token không là số nó có thể là string Chuỗi hằng có thể xác định bằng cặp dấu nháy đơn hoặc dấu nháy kép tùy theo cú pháp của ngôn ngữ lập trình

Cuối cùng, nếu token không phải là chuỗi, thì nó là định danh, từ riêng hoặc ký hiệu riêng Nếu token không được xác định là một trong chúng thì đó là lexical lỗi Lexer không xử lý lỗi của chính nó, vì vậy paser

có token không xác định được tìm thấy Parser sẽ xử lý lỗi

Parser phải hiểu cú pháp của ngôn ngữ lập trình Nó xác định được lỗi cú pháp và chuyển chương trình không lỗi vào cấu trúc dữ liệu bên trong (cây AST), có thể được xử lý bởi bộ phân tích tĩnh

Trang 25

sử dụng, định nghĩa, và sự phụ thuộc của dữ liệu vào chương trình Giải thuật phân tích luồng dữ liệu thực hiện trên đồ thị luồng điều khiển (CFG), tạo từ mã nguồn AST CFG biểu diễn rất cả các đường thực thi

có thể có của chương trình tính toán: các nút biểu diễn một mẫu code

và cạnh biểu diễn điều khiển có thể có để chuyển giữa các mẫu này Khi phân tích được thực hiện mà không thực thi chương trình kiểm tra,

nó không thể xác định chính xác đầu ra của chương trình,…ví dụ tìm

ra đường thực thi trong luồng điều khiển thực sự xảy ra

Kết chương

Trong chương này đã trình bày cơ sở lý thuyết của việc xây dựng cây AST và cách dựa vào cây AST để tìm lỗi

Trang 26

Chương 3 ĐO LƯỜNG CHẤT

LƯỢNG THIẾT KẾ3.1 Làm thế nào để đo lường chất lượng của thiết kế

Trước tiên, cần xác định rằng việc phân tích mã nguồn để đánh giá

chất lượng của thiết kế là tốt hay không tốt chỉ mang tính tương đối Để làm

được điều đó, chúng ta phải xây dựng được một bảng thông tin về mã

nguồn dựa trên cơ sở lý thuyết hướng đối tượng như class, interface,

abstract class, packages, …

Với bảng số liệu đó, chúng ta phân tích và đo lường chất lượng của

thiết kế dựa trên những cơ sở như: khả năng mở rộng của ứng dụng

(Extensibility), khả năng tái sử dụng mã nguồn (Reusability), khả năng duy

trì hoạt động, dễ bảo trì, nâng cấp của sản phẩm (Maintainability)

3.2 Các thông số đánh giá chất lượng thiết kế:

 Số lượng class va interface: Dựa trên số lượng class, abstract class và

interface chúng ta sẽ xác định được khả năng mở rộng của ứng dụng

(Extensibility) Đối với các ứng dụng có số lượng abstract class và

interface nhiều, điều đó đồng nghĩa với khả năng kế thừa và mở rộng

của ứng dụng là lớn

 Afferent Coupling (Ca): Số lượng class bên ngoài một package phụ

thuộc các class bên trong một package Ví dụ: Ta có một package X là

package mà ta đang phân tích, Ca chỉ ra số lượng class bên ngoài sử

dựng class bên trong package X

Trang 27

CC: Số lượng class trong package.

AC: Số lượng abstract class (interface) trong package

A Abstractness

Trang 28

Ce I

Độ ổn định của package nói lên sự phụ thuộc class của package với các package khác Độ ổn định của package càng cao nếu nó không hoặc phụ thuộc rất ít vào các package bên ngoài

Nếu I = 0 (Ce = 0) package không phụ thuộc những package khác, độ

ổn định của package này là tuyệt đối, I = 1 package này phụ thuộc hoàn toàn vào những package khác, độ ổn định không cao

 Quan hệ giữa Abstractness và Instability:

Độ ổn định của sự phụ thuộc: Có hai nguyên nhân tại sao chúng

ta cần thay đổi code trong package

i Bởi vì yêu cầu thay đổi

ii Bởi vì thay đổi trong package khác và dẫn đến chúng ta cần

phải thay đổi theo để chính xác

Điều đó cho ta thấy rằng chúng ta nên phụ thuộc những package mà

có độ ổn định cao Ở đây ta thấy rằng, package B có hai phụ thuộc vào nó, nếu B thay đổi nó có thể yêu cầu phải thay đổi code trong package A va C Chúng ta nói rằng B có độ ổn định cao bởi vì nếu nó thay đổi nhiều package

sử dụng nó thay đổi và người ta thường không muốn làm điều đó

Trang 29

Package A phụ thuộc B và C và vì vậy người ta thích thay đổi A hơn nếu cần thiết Ta nói rằng package A không ổn định.

Kết luận rằng package PHẢI phụ thuộc những package có độ ổn định cao

Ví dụ:

Package A có hai class

Package B có hai interface hoặc hai abstract class

Package C có 1 class va một abstract class

Hình 4.2-3: Độ ổn định của packageDựa vào công thức bên trên, ta thấy được kết quả về độ ổn định của package trong hình vẽ

Độ ổn định của Abstract class: Có nên chăng tất cả phẩn mềm đều

có độ ổn định cao – câu trả lời là không, tất cả phần mềm cần đựa thay đổi cho hợp với yêu cầu thực tế, mở rộng chức năng để ngày càng nâng cao khả năng đáp ứng, như vậy việc mở rộng là bắt buộc và thậm chí đòi hỏi phần mềm phải dễ dàng trong việc mở rộng

Bằng việc tạo một abstract package có độ ổn định cao, từ đó chúng

ta có thể tạo những package thừa kế abstrack có độ ổn đị thấp hơn nhưng

Trang 30

dễ dàng thay đổi Như vậy những package càng về sau có độ ổn định giảm, nhưng ngược lại khả năng thay đổi, mở rộng là rất lớn.

Biểu đồ quan hệ giữa Abstractness và Instability:

Những package có độ ổn định nên được kế thừa và mỏ rộng Hay nói một cách khác, những package không ổn định nên được dùng để chỉnh sữa thay đổi code Vì vậy việc tìm kiếm cơ chế để đánh giá việc cân bằng giữa việc mở rộng và tính ổn định là rất quan trong Nó giúp cho người phát triển ứng dụng có cái nhìn tổng quát và đánh giá nhanh nhất thiết kế cua mình

Như vậy, package muốn ổn định thì có nhiều abstract class

Trang 31

Để dễ tính toán DAI 1 = [0, 1] với 0 co nghĩa là package nằm trên “đường cơ bản”, 1 chỉ rằng package nằm xa so với đường cơ bản.

Biểu thức trên đo lường kiến trúc thiết kế theo mô hình hướng đối tượng Tuy nhiên chúng không phải là cách chính xác và đáng tin cậy để đánh giá đúng đắn về kiến trúc của một ứng dụng Tuy nhiên, ở một chừng mực nào đó, nó được dùng để đo lường sự phụ thuộc giữa các package

3.3 Hiện thực

Công nghệ dùng để thực hiện trong đề tài là java Viêc phân tích mã nguồn dựa trên phân tích cấu trúc cây AST mà đã trình bày ở phần trên Thông qua việc phân tích cây AST chúng ta sẽ xác định tất cả các thông tin cần trong quá trình đánh giá mã nguồn

Hiện thực đo lường chất lượng của thiết kế

Trước tiên, điều quan trọng cần hiểu rằng một bảng kết quả đo lường tốt không đồng nghĩa với việc ứng dụng được thiết kế tốt Tương tự, bảng kết quả đo lường xấu, không có nghĩa là thiết kế của bạn tồi Bảng kết quả không nên dùng như là một chuẩn để đánh giá chất lượng của thiết kế

Mục tiêu chúng ta hiện thực việc đo lường thiết kế để cho phép các designer có thể đo lường thiết kế mà họ đã tạo, hiểu những gì họ làm, kiểm chứng những điều mà họ mong muốn có trong thiết kế của mình

Đo lường chất lượng thiết kế:

Chất lượng của thiết kế có thể được đo lường một phần bởi khả năng

mở rộng, khả năng tái sử dụng và bảo trì của sản phẩm Những điều này được xác định thông qua quan hệ giữa các package trong quá trình thiết kế Thiết kế có khả năng mở rộng cao khi chúng không phụ thuộc những class

mà được hiện thực chi tiết (những class mà hiện thực chi tiết chức năng), cho phép chúng có khả năng đáp ứng hiện thực mới mà không cần chỉnh

Trang 32

sửa hoặc làm sai lệch đi những chức năng đã có Xu hướng độc lập cũng làm tăng khả năng tái sử dụng trong thiết kế, các thành phần khác nhau cùng kế thừa abstract class nhưng chúng được hiện thực khác nhau đáp ứng chức năng cụ thể của nó.

Khả năng bảo trì của thiết kế được cải tiến khi bạn có thể dễ dàng thay đổi mà không làm ảnh hưởng đến những thành phần khác trong cùng một ứng dụng

Như phần phân tích, ta xem xét lại các thông số cần xác định cho mỗi package

 CC – Số lượng class trong một package

 AC – Số lượng abstract class và interface trong một package

 Ca - Số lượng class bên ngoài một package phụ thuộc các class bên trong một package Việc xác định thông số này dựa trên việc import class cua package mà ta đang phân tích

 Ce - Số lượng class bên ngoài một package mà những class bên trong package này phụ thuộc Việc xác định thông số này dựa trên việc import

mà đang sử dụng trong class ta đang phân tích

(0-1) với 0 độ ổn định cao nhất

 D – Khoảng cách từ đường cơ bản (0-1)

Ta lấy một ví dụ để thông qua đó xác định giá trị cụ thể cho những thông số trên Mã nguồn gồm 6 package như hình dưới đây

Trang 33

Hình 4.2-5: Một ví dụ cho các tham số của packageKết quả phân tích như sau:

Hình 4.2-6: Phân tích dựa vào các tham số của packageĐối với package epayment.adapters, chúng ta thấy nó phụ thuộc 2 package khác gồm: epayment.framework, và epayment.response Hơn nữa, package chỉ chứa class nên A = AC/CC=0, và I = Ce/Ce+Ca = 1, D = A + I –

1 = 0 Dựa vào bảng dữ liệu phân tích sự phụ thuộc trên package ta thấy việc sử dụng hay phụ thuộc package này là không an toàn, bởi vì class trong package này có thể thay đổi và như vậy việc các package khác phụ thuộc nó là không an toàn

Đối với package epayment.framework, chúng ta thấy nó không phụ thuộc vào những package khác trong ứng dụng (Ce=0) Tuy nhiên, nó được

Trang 34

sử dụng bởi 5 package khác (Ca=5) Trong khi đó A = 0.83, I=0 dẫn đến D

= 0.17 rất gần với đường cơ bản Ta có thể kết luận rằng việc phụ thuộc trên package này là lý tưởng bởi vì nó độc lập và độ ổn định cao Việc A = 0 cũng chỉ ra rằng nó có khả năng mở rộng theo cách hiện thực mới chứ không chỉnh sửa class đã tồn tại

Kết chương

Chương này trình bày phương pháp đo lường chất lượng thiết kế và các thông số để dựa vào đó có thể biết một thiết kế là tốt hay xấu, cũng như trình bày các bước thực hiện việc đo lường này

Trang 35

Chương 4 PHÁT HIỆN VÀ KHẮC PHỤC LỖI TRONG PHÁT TRIỂN CHƯƠNG TRÌNH

4.1 Làm thế nào để phát hiện lỗi và khắc phục.

Đối với lập trình viên, trong quá trình lập trình, việc bảo đảm không xảy ra lỗi là không thể Với hàng triệu dòng code, việc kiểm tra chất lượng sản phẩm, xem xét và đánh giá mã nguồn càng khó khăn hơn

Đối với phát triển phần mềm hoặc bảo trì sản phẩm Lỗi gây ra cho phần mềm được xem là yếu tố rủi ro nhất và gây hại nhất đến doanh nghiệp bao gồm:

 Giảm hiệu xuất trong quá trình phát triển sản phẩm

 Tăng chi phí cho việc phát triển phần mềm

 Tạo nên nút thắt cổ chai (bottlenecks) trong chu kỳ phát triển phần mềm

Có hai loại lỗi do lập trình thường xảy ra khi phát triển sản phẩm: Lỗi

do con người và lỗi sai về nghiệp vụ Về khía cạnh phân tích mã nguồn để phát hiện lỗi và khắc phục, chúng ta tập trung khắc phục lỗi do con người gây nên do chủ quan cũng như khách quan Hổ trợ cơ chế để cho phép người lập trình tùy biến trong việc kiểm tra lỗi cho mỗi dự án, mỗi module

Đối với lỗi do con người gây ra, ta có thể chia thành hai loại như lỗi biên dịch và lỗi xảy ra trong thời gian chạy Đối với lỗi biên dịch, thật đơn giản là chỉnh sửa mã nguồn và biên dịch lại, nhưng đối với lỗi xảy ra ở thời gian chạy chúng ta không lường trước được và đây chính là thước đo quan trọng nhất cho chất lượng sản phẩm Chúng ta sẽ tập trung phân tích mã nguồn để tìm ra các lỗi tìm tàng cần khắc phục sớm

Trang 36

Dựa trên một số nguồn tài liệu được liệt kê ở phần tham khảo, chúng tôi đưa ra các lỗi cơ bản thường gặp làm ảnh hưởng đến chất lượng sản phẩm (có thể gây ra những lỗi không lường trước) Các lỗi liên quan đến định dạng mã nguồn (coding standard), không được liệt kê

ở đây Ngoài ra tùy đặc thù của từng sản phẩm, dự án hay ngôn ngữ

ta sẽ có nhiều lỗi đặc thù riêng Chúng tôi cũng sẽ đưa ra phương pháp để phân tích mã nguồn cụ thể để kiểm tra bất cứ vấn đề nào gặp phải trong dự án

 CloseConnection: Lỗi khi mở một kết nối đến database nhưng không đóng lại sau khi sử dụng xong

 ObjectComparison: Khi so sanh các đối tượng, không nên dùng phép so sánh bằng (==), hoặc khác (!=) Các phép so sánh này thông thường so sánh địa chỉ mà đối tượng tham khảo đến mà không so sánh nội dung Chúng ta nên dùng phương thức so sánh mà mỗi ngôn ngữ lập trình hổ trợ

 StaticMethod: Đối với static method nên dùng trực tiếp thay vì tạo đối tượng và dùng thông qua đối tượng

 CloseStream: Một số lỗi lập trình thường gặp như mở file nhưng không đóng file, ảnh hưởng đến vấn đề bộ nhớ của ứng dụng

 MethodReturnWrong: Kiểm tra phương thức luôn trả về true, hoặc false Method luôn trả về null (giá trị trả về không được gán giá trị)

 MathError: Một số lỗi về tính toán như: phép chia 0, nhân chia với số thực dấu chấm động

 RecursiveLoop: Vòng lặp không xác định điểm dừng

 MethodNullArgument: Các method không check null cho các tham số truyền vào

Trang 37

 NullPointerException: Khai báo một đối tượng nhưng không khởi tạo đối tượng là nguyên nhân rất phổ biến gây nên lỗi Nói cách khác, trước khi

sử dụng đối tượng, đảm bảo rằng đối thượng là khác null

 Và rất nhiều lỗi khác

4.2 Thực hiện

Như đề cập ở phần lý thuyết Cơ sở cho việc phân tích mã nguồn là cây AST Làm thế nào để dựa vào cây AST để phát hiện các vấn đề lỗi, báo cáo kết quả … Chúng ta sẽ đi phân tích một vài ví dụ cụ thể

CloseConnection:

Lỗi xảy khi ta mở một kết nối đến database và thao tác dữ liệu, sau khi hoàn tất chúng ta không đóng kết nối Vấn đề này rất thường xảy ra và ảnh hưởng đến sự hoạt động ổn định của sản phẩm

Ví du:

public void closeConnection () {

try {

Connection con = DriverManager.getConnection(url);

String sql = "select * from person";

Trang 38

Trong đoạn code trên, ta thấy việc mở kết nối đến database nhưng không đóng kết nối sau khi hoàn tất Trước tiên, điều cần làm là đưa ra giải thuật để giải quyết vấn đề trên Ta thấy rằng, nếu trong một method có một câu lệnh mở một kết nối đến database thì phải tồn tại một câu lệnh đóng kết nối Và method trên vi phạm quy ước trên.

Với đoạn code trên, sau khi phân tích ta được cây AST như hình vẽ sau:

Hình 5.2-1: Cây AST cho một đoạn code ví dụ 1Các bước để phân tích và xác định lỗi:

1 Duyệt qua tất cả các method (METHOD_DEF) trong mỗi class Với mỗi method

2 Tìm DOT type, nơi chúng ta gọi hàm hay truy cập biến

3 Kiểm tra nếu method gọi là getConnection Nếu không phải, bỏ qua và tìm kiếm DOT type kế tiếp Nếu method gọi là getConnection, ta đánh dấu và tìm hàm close trong cùng method ta đang duyệt Nếu có, mothod trong class này là hợp

Trang 39

lệ, nếu không nó vi phạm và chúng ta ghi nhớ tên class, tên method và thậm chí dòng, cột để có biện pháp khắc phục.

Lỗi compare object dùng phép so sánh ==:

Trong java, phép so sánh == chỉ được dùng để so sánh giá trị Đối với các đối tượng, nếu dung phép so sánh ==, trình biên dịch hiểu là chúng

ta đang so sánh địa chỉ mà đối tượng đang trỏ đến chứ không phải so sánh nội dung của chúng

Trang 40

Hình 5.2-2: Cây AST cho phân tích một đoạn code ví dụ 2

Các bước để phân tích và xác định lỗi:

1 Duyệt qua tất cả các method (METHOD_DEF) trong mỗi class Với mỗi method

2 Tìm EQUAL type, nơi chúng ta thực hiện phép so sánh ==

3 Kiểm tra nếu biến a và b có loại dữ liệu là OBJECT Nếu đúng việc sử dụng == là sai, nếu không việc sử dụng == là hợp lệ.Chi tiết của các giải thuật, cũng như thủ thuật lập trinh, cách duyệt qua các node có thể tham khảo chi tiết ở mã nguồn

4.3 Phương pháp nhận dạng những lỗi bảo mật của chương trình

Lỗi bảo mật là những lỗ hổng của ứng dụng mà dựa vào đó hacker

có thể dành quyền truy cập ứng dụng, hoặc có được những thông tin tài khoản của hệ thống Đặc biệt, đối với các website, việc hacker đột nhập dễ

Ngày đăng: 12/02/2021, 22:07

TỪ KHÓA LIÊN QUAN

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

TÀI LIỆU LIÊN QUAN

🧩 Sản phẩm bạn có thể quan tâm

w