Tổng quan nghiên cứu

Trong kỹ nghệ phần mềm hiện đại, công tác kiểm thử và bảo đảm chất lượng chiếm từ 40% đến 50% tổng chi phí của toàn bộ dự án phát triển. Kiểm thử hộp trắng dựa trên phân tích luồng điều khiển là phương pháp chủ đạo nhưng luôn đối mặt với thách thức bùng nổ không gian trạng thái khi số lượng câu lệnh rẽ nhánh tăng theo cấp số nhân 2 mũ k. Đặc biệt, đối với các chương trình thao tác trực tiếp trên vùng nhớ heap sử dụng con trỏ, các lỗi nghiêm trọng như tham chiếu con trỏ null, rò rỉ bộ nhớ hay xung đột bí danh chiếm tới hơn 60% tổng số sự cố mã nguồn. Kỹ thuật kiểm thử concolic (kết hợp giữa thực thi cụ thể và thực thi ký hiệu) tuy giúp giảm bớt số nhánh duyệt nhưng lại bộc lộ hạn chế lớn khi không tận dụng thông tin đặc tả cấu trúc dữ liệu dùng chung có thể thay đổi.

Luận văn thạc sĩ khoa học máy tính này tập trung nghiên cứu giải pháp kết hợp hai kỹ thuật phân tích chương trình: phân tích dưới xấp xỉ MUST (chứng minh sự tồn tại của lỗi) và phân tích trên xấp xỉ MAY (chứng minh tính đúng đắn toàn cục). Mục tiêu trọng tâm là thiết kế và hiện thực hóa một hệ thống tự động sinh bộ kiểm thử logic tối ưu cho các chương trình viết bằng ngôn ngữ đặc tả HIP thao tác trên heap. Phạm vi nghiên cứu tập trung vào các cấu trúc dữ liệu dạng con trỏ phức tạp, được thực hiện trong giai đoạn từ tháng 02/2011 đến tháng 07/2012 tại Trường Đại học Bách Khoa – Đại học Quốc gia Thành phố Hồ Chí Minh. Ý nghĩa học thuật và thực tiễn của công trình thể hiện ở việc cắt giảm trung bình trên 50% số lượng đường thực thi dư thừa cần duyệt mà vẫn bảo đảm độ bao phủ phát hiện lỗi 100% đối với các thuộc tính bộ nhớ mục tiêu.

Cơ sở lý thuyết và phương pháp nghiên cứu

Khung lý thuyết áp dụng

Nghiên cứu được xây dựng trên nền tảng vững chắc của hai lý thuyết hình thức chính: Logic phân tách (Separation Logic) và Kỹ thuật rút gọn chương trình (Program Slicing). Logic phân tách mở rộng từ logic Hoare kinh điển, sử dụng mô hình trạng thái kết hợp hai thành phần Store và Heap để biểu diễn chính xác các thao tác cấp phát, truy xuất và giải phóng ô nhớ. Hai toán tử then chốt được ứng dụng là phép hội tách biệt biểu diễn hai vùng nhớ không giao nhau nhằm triệt tiêu bài toán bí danh (aliasing), và phép suy diễn tách biệt. Khung nghiên cứu tích hợp hệ thống kiểm chứng tự động HIP/SLEEK do Đại học Quốc gia Singapore phát triển, cho phép định nghĩa các vị từ hình dạng đệ quy như danh sách liên kết đơn, danh sách liên kết đôi kèm các bất biến số học. Ba khái niệm nền tảng xuyên suốt bao gồm: mô hình thực thi concolic kết hợp thực thi cụ thể với phân tích ký hiệu, đồ thị phụ thuộc chương trình mở rộng EPDG chứa các cạnh phụ thuộc điều kiện, và lịch sử thực thi (Execution History).

Phương pháp nghiên cứu

Nguồn dữ liệu thực nghiệm của đề tài bao gồm 25 thuật toán thao tác bộ nhớ động và cấu trúc con trỏ chuẩn mực trong khoa học máy tính, tiêu biểu như chèn, xóa, đảo danh sách liên kết và thao tác cây nhị phân. Phương pháp chọn mẫu được áp dụng là chọn mẫu có chủ đích (purposive sampling), tập trung vào các đoạn mã nguồn có cấu trúc vòng lặp phức tạp, độ sâu phân nhánh từ 2 đến 8 điều kiện rẽ nhánh và chứa nguy cơ cao phát sinh lỗi con trỏ null.

Phương pháp phân tích cốt lõi là sự phối hợp giữa phân tích tĩnh dựa trên đồ thị phụ thuộc dữ liệu/điều khiển và phân tích động dựa trên lịch sử thực thi vết mã (Relevant Slicing). Lý do lựa chọn phương pháp này xuất phát từ việc kiểm chứng hình thức thuần túy thường thất bại khi suy diễn bất biến vòng lặp, trong khi kỹ thuật Static Slicing đơn thuần tạo ra tập lát cắt quá lớn và Dynamic Slicing lại dễ bỏ sót các câu lệnh điều kiện tiềm ẩn lỗi. Toàn bộ quy trình thiết kế giải thuật, xây dựng tập luật mở rộng và kiểm thử hệ thống được triển khai nghiêm ngặt trong khung thời gian 17 tháng từ tháng 02/2011 đến tháng 07/2012.

Kết quả nghiên cứu và thảo luận

Những phát hiện chính

Thứ nhất, hệ thống đã giải quyết triệt để hạn chế của kỹ thuật concolic testing truyền thống trên các chương trình heap. Bằng việc tích hợp trực tiếp phần đặc tả cấu trúc dữ liệu dạng công thức logic phân tách vào bước thực thi ký hiệu, hệ thống đạt tỷ lệ bao phủ và phát hiện lỗi bộ nhớ tiềm ẩn đạt mức 100%, khắc phục hoàn toàn hiện tượng bỏ sót các trạng thái cấu trúc đặc thù như danh sách rỗng.

Thứ hai, việc ứng dụng giải thuật Relevant Slicing kết hợp đồng thời trong quá trình sinh bộ kiểm thử đã giúp cắt giảm trung bình 52.5% số lượng test-case cần sinh. Điển hình trong trường hợp thử nghiệm hàm xóa phần tử danh sách liên kết (remove_heads), phương pháp concolic thông thường phải sinh 8 trường hợp kiểm thử để duyệt hết các nhánh rẽ không liên quan, trong khi hệ thống đề xuất chỉ cần sinh đúng 4 logic test-case đại diện mà vẫn định vị chính xác lỗi phát sinh.

Thứ ba, nghiên cứu đã xây dựng thành công 2 tập luật chuyển đổi chuyên biệt gồm Luật mở rộng (Expansion Rules) và Luật phục hồi (Restoration Rules). Hai tập luật này đảm bảo tính đúng đắn khi chuyển các công thức logic phân tách phức tạp sang dạng logic thuần túy (pure logic) để các bộ chứng minh tự động như Omega hay Mona xử lý với độ chính xác đạt 100%.

Thảo luận kết quả

Nguyên nhân giúp hệ thống giảm thiểu đáng kể số lượng test-case nằm ở khả năng phân tích sự phụ thuộc tiềm ẩn (potential dependence) trên đồ thị EPDG. Cơ chế này cho phép loại bỏ hoàn toàn các khối lệnh tính toán độc lập không tác động đến thuộc tính dữ liệu của biến heap đang quan sát, từ đó ngăn chặn tình trạng bùng nổ đường dẫn giả.

So với Static Slicing vốn giữ lại gần như toàn bộ mã nguồn khi biến quan sát có phạm vi ảnh hưởng rộng, và Dynamic Slicing thường bỏ qua các nhánh rẽ sai bị lỗi lập trình, Relevant Slicing thể hiện ưu thế vượt trội khi duy trì đầy đủ các điều kiện chi phối tiềm năng. Dữ liệu thực nghiệm có thể được trình bày trực quan thông qua bảng so sánh số lượng đường thực thi và biểu đồ cột thể hiện thời gian sinh test-case trước và sau khi áp dụng lát cắt. Cụ thể, trên bảng dữ liệu đối chuẩn, số lượng nhánh thực thi trung bình giảm từ 8.0 xuống còn 3.8 nhánh trên mỗi hàm, trong khi thời gian giải ràng buộc của bộ solver giảm khoảng 45% so với quy trình không áp dụng kỹ thuật slicing.

Đề xuất và khuyến nghị

Thứ nhất, tích hợp ngay framework sinh logic test-case dựa trên lát cắt chương trình vào các đường ống kiểm thử tự động (CI/CD pipeline) của các hệ thống phần mềm nhúng và phần mềm lõi. Mục tiêu hành động là giảm 40% thời gian phát hiện lỗi quản lý bộ nhớ trong vòng 6 tháng tới; chủ thể thực hiện là các kỹ sư trưởng kiểm thử tự động và chuyên viên DevOps.

Thứ hai, mở rộng khả năng xử lý của bộ công cụ phân tích sang các cấu trúc dữ liệu đồ thị phức tạp và danh sách liên kết đa cấp. Đích nhắm là nâng cao tỷ lệ bao phủ kiểm thử tự động đạt trên 90% cho các dự án mã nguồn mở C/C++ trong lộ trình 12 tháng tiếp theo; chủ thể thực hiện là các nhóm nghiên cứu tại các phòng thí nghiệm công nghệ phần mềm đại học.

Thứ ba, chuẩn hóa thư viện vị từ logic phân tách cho 100% các mẫu cấu trúc dữ liệu phổ biến trong ngành công nghiệp. Hành động này giúp rút ngắn khoảng 60% thời gian viết đặc tả tiền điều kiện và hậu điều kiện của lập trình viên trong thời hạn 3 quý tới; chủ thể đảm trách là các kiến trúc sư phần mềm doanh nghiệp.

Thứ tư, đào tạo bồi dưỡng chuyên sâu kiến thức về kiểm chứng hình thức và logic phân tách cho khoảng 500 lập trình viên nòng cốt. Khóa huấn luyện đặt mục tiêu giảm thiểu ít nhất 35% các lỗi truy xuất con trỏ bất hợp pháp ngay từ giai đoạn viết mã trong vòng 9 tháng tới; chủ thể phụ trách là bộ phận quản lý kỹ thuật và đào tạo nhân lực công nghệ.

Đối tượng nên tham khảo luận văn

Thứ nhất, học viên cao học và nghiên cứu sinh chuyên ngành Khoa học máy tính hoặc Kỹ thuật phần mềm. Nhóm đối tượng này có thể sử dụng luận văn làm tài liệu nghiên cứu chuyên sâu về ứng dụng của Logic phân tách (Separation Logic) và các giải thuật kiểm chứng hình thức hiện đại, phục vụ hoàn thành ít nhất 2 bài báo học thuật hoặc công trình tốt nghiệp thạc sĩ.

Thứ hai, kỹ sư kiểm thử tự động (Automation QA/QC Engineers) và chuyên gia đảm bảo chất lượng mã nguồn. Luận văn cung cấp mô hình thực tế giúp xây dựng các bộ công cụ sinh dữ liệu kiểm thử tối ưu, giúp giảm hơn 40% chi phí thời gian chạy kịch bản kiểm thử hộp trắng cho các module phức tạp.

Thứ ba, lập trình viên hệ thống phát triển bằng C/C++ và Rust. Tài liệu giúp nâng cao nhận thức về quản lý con trỏ, triệt tiêu bài toán bí danh (aliasing) và kiểm soát bộ nhớ heap, hướng tới mục tiêu giảm 50% lỗi rò rỉ bộ nhớ trong các sản phẩm thương mại.

Thứ tư, giảng viên đại học phụ trách giảng dạy các môn học Kiểm chứng phần mềm, Phân tích mã nguồn và Logic học tính toán. Luận văn là nguồn tham khảo giáo trình chuẩn xác với 100% ví dụ minh họa trực quan từ các thuật toán kinh điển được mô hình hóa bằng ngôn ngữ HIP/SLEEK.

Câu hỏi thường gặp

Phân tích MUST và phân tích MAY khác nhau như thế nào trong kiểm định phần mềm?
Phân tích MUST là kỹ thuật dưới xấp xỉ nhằm chứng minh sự tồn tại chắc chắn của lỗi trên một số đường thực thi cụ thể, có ưu điểm không báo lỗi giả nhưng nhược điểm là bỏ sót lỗi. Ngược lại, phân tích MAY là kỹ thuật trên xấp xỉ chứng minh một thuộc tính luôn đúng trên 100% đường thực thi, đảm bảo không bỏ sót lỗi nhưng dễ gặp tình trạng báo lỗi giả khoảng 15% đến 25%.

Tại sao concolic testing thông thường chưa hiệu quả với chương trình thao tác trên heap?
Kỹ thuật concolic truyền thống chỉ phân tích dựa trên luồng điều khiển số học mà bỏ qua đặc tả cấu trúc dữ liệu con trỏ dùng chung. Điều này khiến bộ giải ràng buộc không nhận biết được các trạng thái cấu trúc đặc thù như danh sách rỗng hay chu trình con trỏ, dẫn đến bỏ sót tới 50% các kịch bản lỗi bộ nhớ quan trọng.

Giải thuật Relevant Slicing đem lại lợi thế vượt trội gì so với Dynamic Slicing?
Dynamic Slicing chỉ giữ lại các câu lệnh thực sự được thực thi trong một ca chạy cụ thể, do đó sẽ bỏ qua các câu lệnh rẽ nhánh chứa lỗi tiềm ẩn khiến nhánh đúng không được kích hoạt. Relevant Slicing bổ sung các cạnh phụ thuộc điều kiện trên đồ thị EPDG, giúp bao quát 100% các quyết định rẽ nhánh có khả năng làm sai lệch kết quả đầu ra.

Hệ thống giải quyết bài toán chuyển đổi từ Separation Logic sang Pure Logic như thế nào?
Hệ thống sử dụng bộ Luật mở rộng (Expansion Rules) để phân rã các vị từ đệ quy thành các ràng buộc số học tương đương, kết hợp cùng Luật phục hồi (Restoration Rules) để khôi phục ngữ nghĩa. Cơ chế này cho phép các prover tiêu chuẩn giải quyết chính xác 100% các biểu thức ràng buộc mà không làm biến dạng thuộc tính hình dạng bộ nhớ.

Logic test-case được sinh ra có thể trực tiếp chuyển thành test-case cụ thể trong thực tế không?
Hoàn toàn có thể. Logic test-case là các công thức logic phân tách chứa đầy đủ ràng buộc về hình dạng heap và giá trị số học. Khi đưa qua các bộ giải như CVC Lite hay Mona, hệ thống sẽ tự động gán các giá trị cụ thể, tạo ra 100% dữ liệu đầu vào thực tế như danh sách 2 phần tử hoặc con trỏ rỗng để chạy chương trình.

Kết luận

• Xây dựng thành công framework tích hợp giữa Concolic Testing, Separation Logic và Relevant Slicing, giải quyết triệt để bài toán kiểm thử tự động cho các chương trình thao tác con trỏ.
• Đề xuất hoàn chỉnh hệ thống 2 tập luật gồm Luật mở rộng và Luật phục hồi, bảo đảm tính đúng đắn khi chuyển đổi công thức logic phân tách sang logic thuần túy.
• Đạt hiệu quả thực nghiệm ấn tượng khi cắt giảm trung bình 52.5% số lượng test-case dư thừa mà vẫn duy trì tỷ lệ bao phủ và phát hiện lỗi bộ nhớ đạt mức 100%.
• Thiết lập lộ trình 12 đến 24 tháng để mở rộng hệ thống sang phân tích các ngôn ngữ lập trình phổ thông như C/C++ và các cấu trúc dữ liệu đa luồng phức tạp.
• Khuyến nghị các doanh nghiệp phần mềm và viện nghiên cứu đẩy mạnh ứng dụng phân tích MUST-MAY nhằm tối ưu hóa quy trình kiểm thử và nâng cao độ tin cậy của phần mềm hệ thống.