Giảm thiểu hành vi không xác định trong ngôn ngữ C: Nỗ lực biến C thành ngôn ngữ an toàn bộ nhớ
Tại hội nghị Kernel Recipes 2026, giáo sư Martin Uecker đã trình bày về vấn đề hành vi không xác định (undefined behavior) trong ngôn ngữ C và liệu C có thể trở thành một ngôn ngữ an toàn bộ nhớ trong tương lai. Ông cũng điểm qua những cải tiến của chuẩn C23 và dự thảo C2y đang loại bỏ dần các hành vi không xác định.

Giảm thiểu hành vi không xác định trong ngôn ngữ C
Tại hội nghị Kernel Recipes 2026, giáo sư Martin Uecker — một chuyên gia về kỹ thuật y sinh nhưng đồng thời là người dùng Linux lâu năm và phát triển phần mềm mã nguồn mở cho máy chụp cộng hưởng từ (MRI) — đã có bài trình bày đáng chú ý về ngôn ngữ C. Ông tập trung vào vấn đề hành vi không xác định (undefined behavior) và đặt câu hỏi liệu C có thể được cải tiến để trở thành ngôn ngữ an toàn bộ nhớ hay không.
Vì sao C vẫn quan trọng vào năm 2026?
Theo Uecker, C vẫn là một ngôn ngữ tuyệt vời vì nhiều lý do. Nó có tính di động cao, ổn định lâu dài, biên dịch nhanh và mã máy sinh ra cũng chạy nhanh. Điều đặc biệt là nguyên tắc "thấy gì được nấy" — nhìn vào mã C, lập trình viên có thể hình dung khá rõ máy tính sẽ thực thi những gì.
Bên cạnh đó, hệ sinh thái công cụ dành cho C rất phong phú, và ngôn ngữ này luôn biết cách "nhường đường" khi cần thiết, cho phép lập trình viên can thiệp sâu vào phần cứng.
Lịch sử và nguồn gốc của hành vi không xác định
Martin Uecker tại hội nghị Kernel Recipes
Uecker giải thích rằng lịch sử lâu đời của C đã ảnh hưởng sâu sắc đến diện mạo ngôn ngữ ngày nay. Chuẩn C89 ra đời trong bối cảnh phải hỗ trợ vô số loại phần cứng khác nhau — từ máy dùng biểu diễn số nguyên dấu-độ-lớn (signed-magnitude), bù một (one's-complement), bộ nhớ phân đoạn, cách biểu diễn con trỏ kỳ lạ, cho đến những kích thước kiểu dữ liệu gây bất ngờ. Một số máy Honeywell thậm chí có byte 9 bit.
Để giải quyết vấn đề này, ủy ban chuẩn hóa đã định nghĩa ngữ nghĩa của ngôn ngữ dựa trên một máy trừu tượng (abstract machine). Mọi thao tác được coi như thực thi trên máy trừu tượng ấy, dù nó có thể không khớp hoàn toàn với phần cứng thực tế. Chỉ có hành vi quan sát được (observable behavior) — như truy cập biến volatile — mới bắt buộc phải tuân theo máy trừu tượng; mọi thứ khác chỉ cần tạo ra kết quả cuối cùng tương đương.
Chuẩn C dành rất nhiều tự do cho người phát triển trình biên dịch. Hành vi không xác định xuất hiện khi chương trình làm điều gì đó không di động hoặc không được chuẩn quy định. Trong trường hợp đó, chuẩn C89 tuyên bố rằng nó "không áp đặt bất kỳ yêu cầu nào" lên bản thân trình biên dịch.
Vấn đề "quỷ mũi" (nasal demons)
Vấn đề nan giải, theo Uecker, là chuẩn C cho phép trình biên dịch làm bất cứ điều gì khi gặp hành vi không xác định — thậm chí đến mức triệu hồi "quỷ mũi" theo cách nói ví von nổi tiếng trong giới lập trình. Nếu chương trình chứa bất kỳ hành vi không xác định nào, theo quan điểm của những người viết trình biên dịch, nó không còn ngữ nghĩa mong đợi nào cả.
Ông đưa ra một ví dụ đơn giản:
extern int x;
int f(int a, int b)
{
x = b ? 42 : 43;
return a / b;
}
Nếu b bằng không, phép chia là hành vi không xác định. Vậy trình biên dịch có quyền bỏ qua toàn bộ phép kiểm tra và chỉ thực thi x = 42 hay không? Trên thực tế, có những trình biên dịch làm đúng như vậy.
Tuy nhiên, khi thay đổi ngữ cảnh một chút:
extern void g(int x);
int f(int a, int b)
{
g(b ? 42 : 43);
return a / b;
}
Nếu hàm g() gọi exit() khi b bằng không, phép chia sẽ không bao giờ xảy ra và chương trình không có hành vi không xác định. Vì vậy, việc bỏ phép kiểm tra và truyền thẳng giá trị 42 cho g() là hành vi lỗi của trình biên dịch.
Một trường hợp thú vị khác liên quan đến việc "du hành thời gian" — trình biên dịch có thể kéo phép chia lên trước phép gán cho biến volatile hay không. Chuẩn C23 đã bổ sung quy định "không du hành thời gian" để cấm điều này, trong khi C++ yêu cầu gọi std::observable_checkpoint() một cách tường minh.
Nỗ lực cải thiện tình hình
Để giải quyết những vấn đề này, ủy ban C đã thành lập ba nhóm nghiên cứu chuyên về mô hình đối tượng bộ nhớ, an toàn bộ nhớ và hành vi không xác định. Hiện có khoảng 100 trường hợp hành vi không xác định trong chuẩn C, nhưng dự thảo C2y đang trong quá trình hoàn thiện đã loại bỏ được 45 trường hợp.
Hệ sinh thái công cụ phát hiện lỗi cũng ngày càng phong phú: cảnh báo trình biên dịch, công cụ phân tích tĩnh, sanitizer, công cụ dựa trên LLM, và cả phương pháp xác minh hình thức. GCC giờ đây có thể cảnh báo về nhiều tình huống tràn bộ đệm tiềm ẩn.
An toàn bộ nhớ: Ba bài toán con
Uecker phân tích vấn đề an toàn bộ nhớ thành ba bài toán con:
- An toàn kiểu (type safety): C có hệ thống kiểu mạnh, và các vấn đề còn lại có thể khắc phục được. Union không có thẻ (tagless union) có thể gây nhầm lẫn kiểu, nhưng trình biên dịch có thể thực thi kiểu với các chú thích bổ sung.
- An toàn không gian bộ nhớ (spatial memory safety): Đây là bài toán đã được giải quyết một phần; trình biên dịch có thể kiểm tra biên mảng trong nhiều tình huống.
- An toàn thời gian bộ nhớ (temporal memory safety): Khó hơn nhiều trong C, và Rust rõ ràng có lợi thế ở đây. Tuy nhiên, các kiến trúc như CHERI và công cụ như Fil-C có thể giúp phát hiện nhiều lỗi loại này.
C23 và C2y: Những bước tiến cụ thể
Uecker kết luận rằng C vẫn là một ngôn ngữ sống động và không ngừng cải thiện. Chuẩn C23 đã loại bỏ nhiều tính năng có vấn đề, bao gồm định nghĩa hàm kiểu cũ (K&R), hỗ trợ máy dấu-độ-lớn và bù một, cùng với trigraph. Nó bổ sung kiểu số nguyên chính xác theo bit, các phép toán số nguyên có kiểm tra, và nhiều cải tiến khác.
Dự thảo C2y sẽ đi xa hơn nữa với dải case, vòng lặp for có tên, macro _Countof() để xác định độ dài mảng, và rất nhiều nỗ lực "loại bỏ quỷ". Nó sẽ chưa đạt được an toàn bộ nhớ hoàn toàn cho C, nhưng đó là điều có thể xảy ra trong tương lai và sẽ trở nên thực tế hơn theo thời gian.
"C vẫn là ngôn ngữ sống động và đang không ngừng cải thiện. Mỗi bước tiến nhỏ đều đưa chúng ta đến gần hơn với mục tiêu an toàn bộ nhớ."
Đối với cộng đồng lập trình viên Việt Nam, đây là thông tin đáng chú ý: nếu bạn đang làm việc với C trong các dự án nhúng, hệ điều hành, hoặc cơ sở hạ tầng quan trọng, việc hiểu rõ hành vi không xác định và các cải tiến mới từ chuẩn C sẽ giúp mã nguồn an toàn và ổn định hơn. Các nhóm làm việc của ủy ban C luôn hoan nghênh sự tham gia của những người quan tâm.
Bài viết liên quan

Công nghệ
Mô hình AI hàng đầu giỏi Vật lý đến đâu? Nghiên cứu mới chỉ ra các bài kiểm tra hiện hành đang đánh giá sai
16 tháng 9, 2026

Công nghệ
Nộp đơn xin việc lẽ ra nên khó hơn. Thật đấy
25 tháng 8, 2026

Công nghệ
Anthropic triển khai chương trình bảo vệ hạ tầng trọng yếu và mã nguồn mở trước các mối đe dọa từ AI
08 tháng 10, 2026