Hiểu mã C di sản

Di sản C, thường là mã C, nhiều thập kỷ tuổi, tạo thành xương sống của vô số hệ thống nhúng, hệ điều hành và ứng dụng kinh doanh. Những cơ sở mã này ban đầu được viết dưới những sự hạn chế về trí nhớ hạn chế, bộ xử lý chậm, và các công cụ thô sơ, chúng có thể hoạt động không thể tin được, chúng thường chứa một vật chủ của các vấn đề: biến thế giới rải rác khắp các mô- đun, điều kiện sâu sắc, số lượng ma thuật, và sự phụ thuộc lớn vào phần mở rộng đặc biệt.

Trước khi chạm vào một dòng riêng lẻ, không thể thương lượng một cách kỹ lưỡng sự hiểu biết về hệ thống hiện có. Hãy đọc tài liệu (nếu nó tồn tại), các chuyên gia về miền phỏng vấn, và chạy mã dưới bộ gỡ lỗi để quan sát dòng chảy của nó. Hãy chọn ra những phần nào khó gắn vào phần cứng hoặc hệ điều hành. Giai đoạn này phòng tránh sự ngắt quãng ngẫu nhiên và giúp ưu tiên việc cố gắng sửa chữa lỗi.

Những chiến lược để phục hồi hữu hiệu

Những chiến lược sau đây tạo thành một khuôn khổ có hệ thống cho di sản C hiện đại, và mỗi phương pháp này giảm thiểu nợ kỹ thuật trong khi giữ chức năng cơ bản của phần mềm.

1. điều khiển một cuộc thi mã hóa

Một bảng kiểm tra mã xác định chính xác điểm đau. Dùng công cụ phân tích tĩnh để tự động phát hiện lỗi, dấu hiệu an ninh và vi phạm tiêu chuẩn mã hóa hiện đại. Lấy thí dụ, [FLT: 0] kiểm tra [FLT: 0] [FLT: 1]] bắt gặp các thông tin liên kết l vô giá trị đối chiếu, bộ đệm tràn ngập, và biến không dùng. Gọi bộ phân tích [FLT:] cung cấp kiểm tra đường dẫn sâu hơn. Chạy mã qua các công cụ này và sau khi thay đổi để bảo đảm không có sự tái tạo.

Trong khi kiểm tra, cũng thanh tra hệ thống xây dựng. Hiện đại hóa Tập tin Tạo hóa hoặc Thợ Tạo Mẫu để hỗ trợ việc chuyển đổi ngôn ngữ qua mạng và cho phép bộ biên dịch cảnh báo như [FLT: 0]. Tài liệu kiến trúc và tạo một đồ thị phụ thuộc - điều này sẽ hướng dẫn các nỗ lực tùy chỉnh sau này.

2. Thiết lập các tiêu chuẩn phối hợp thời nay

Chấp nhận một tiêu chuẩn mã hóa được công nhận để mang lại sự nhất quán qua cơ sở mật mã. Hướng dẫn [FLT: 0] [FLTRA C [FLT: 1] [FLT: 1] (thường được dùng trong hệ thống tự động và an toàn) giảm hành vi không xác định và tăng khả năng đọc. Đối với các dự án tổng quát, theo sát tiêu chuẩn C - ít nhất là C11, tốt nhất C17. Tính năng này cho phép truy cập các tính năng như [FL:1], cấu trúc vô danh và chỉ (C11).

Tiêu chuẩn hoá các hội nghị tên (v. g., ) cho chức năng và biến, cho vĩ mô, indentation (b tương ứng với khoảng trống), và kiểu chú thích (dùng Doxygen hay tương tự). Hãy đặt những quy tắc này qua thanh [FLT: 0] trong đường dẫn liên tục kết.

3. Đổi cỡ mã

Di sản C thường chứa các chức năng khối lục phân bao gồm hàng trăm hay hàng ngàn dòng. Chia chúng thành các mô- đun riêng . Hãy dùng tập tin tựa đề để tuyên bố giao diện công cộng và tập tin nguồn để thực hiện. Chẳng hạn, chia một tập tin có thể quản lý mạng và tập tin I/O thành các mô- đun riêng . [FL:5] và [FL:6] [FL:6].

Sự phân tách cũng có nghĩa là giảm biến toàn cục. Thay thế chúng bằng trạng thái cục bộ được thông qua các đối số chức năng hoặc con trỏ. Tính năng này làm cho quan hệ phụ thuộc rõ ràng và đơn vị thử nghiệm khả năng. Giới thiệu kiểu hiệu quả (đi tới khai báo trong đầu trang, định nghĩa chỉ trong tập tin để ẩn chi tiết thực hiện.

// Before: monolithic, global state
int buffer[256];
int index = 0;
void process_data() { /* manipulates global buffer and index */ }

// After: encapsulated module
// buffer.h
typedef struct Buffer Buffer;
Buffer* buffer_create(size_t size);
int buffer_push(Buffer* b, int value);
void buffer_destroy(Buffer* b);

// buffer.c
struct Buffer {
 int* data;
 size_t size;
 size_t index;
};
Buffer* buffer_create(size_t size) { ... }

4 Thay thế hàm bị phản đối và không an toàn

Thư viện tiêu chuẩn C chứa một số chức năng nổi tiếng không an toàn hoặc bị bác bỏ hoặc nản lòng trong mã hóa bảo mật hiện đại. Thay thế chúng một cách có hệ thống:

  • hoặc
  • hoặc
  • + với giới hạn trường rộng

Những thay đổi này loại bỏ các bộ đệm tràn ngập, một nguồn chính của các điểm yếu bảo mật. Ngoài ra, tắt các chức năng cũ bằng cách xác định trên các cửa sổ hoặc bằng cách sử dụng cờ biên dịch để xử lý các chức năng bị lỗi. [FLT: 0] DRY Cding Standard cung cấp một danh sách toàn diện các thay thế an toàn.

5. Quản lý bộ nhớ cải thiện

Việc định vị bộ nhớ động trong di sản C thường là lỗi-prone. Các vấn đề thông thường bao gồm quên bộ nhớ miễn phí, tự do gấp đôi, và tùy chỉnh bộ nhớ. Quản lý bộ nhớ với những thực hành này:

  • Dùng thay vì khi cần bộ nhớ không kích hoạt.
  • Luôn luôn kiểm tra giá trị trả về chức năng định vị .
  • Tạo các hàm gói theo dõi sự phân vùng (v. d., mà hủy bỏ khi thất bại).
  • Nhận một mô hình quyền sở hữu nhất quán: tài liệu sở hữu bộ nhớ và chịu trách nhiệm về việc giải phóng nó.
  • Dùng công cụ như Valgrind (Memcheck) or addressSanitzer (AAAan) để phát hiện rò rỉ và truy cập ngoài giới hạn trong khi thử nghiệm.

Trong các phần nghiêm trọng của hiệu suất, hãy cân nhắc sử dụng các bộ đệm hay máy điều hòa tĩnh để tránh phân mảnh và trên đầu. để thay thế các hệ thống với bộ nhớ bị ràng buộc, thay thế sự định vị năng động bằng các hồ bơi đã được tạo ra trước.

6 Nhận nuôi một cách an toàn hơn

Chỉ điểm là một thanh kiếm hai lưỡi, hiện đại hóa cách sử dụng của chúng để giảm khả năng lỗi:

  • Dùng cho tham số hàm không thay đổi. Tính năng này làm cho giao kèo rõ ràng hơn và giúp bộ biên dịch tối ưu hóa.
  • Điều chỉnh con trỏ cho đối tượng không đặt tên bằng . Tính năng này hiệu lực véc- tơ hoá tốt hơn.
  • Khi đọc dòng chữ theo tên dòng, hãy dùng thay vì dùng lệnh [xxxxxxxxxxxx để tránh phạm tội bí danh nghiêm ngặt.
  • Thay thế bộ chỉnh hàm bộ cuộn với bộ chỉ trỏ hàm đúng để tránh hành vi không xác định.
  • Dùng bộ phận dãy linh hoạt (C99) thay cho (các dãy kích cỡ ở cuối struct).
// Avoid: casting void* to misaligned type
int value = *(int*)(byte_buffer + offset); // potential UB

// Prefer: memcpy
int value;
memcpy(&value, byte_buffer + offset, sizeof(value));

7 Lỗi tối ưu hóa

Di sản C thường dùng hỗn hợp , mã trả lại và các tình trạng lỗi toàn cầu.

  • Dùng những kiểu trả về được liệt kê cho hàm (v. d., .
  • Tránh trả lại cho các mã lỗi; các số nguyên ký cho phép các giá trị tiêu cực cho lỗi.
  • Đối với hệ thống phức tạp, thực hiện một mô hình nhỏ nhẹ sử dụng (nhưng sử dụng khả năng kiểm soát lưu thông phức tạp).
  • Ghi lưu lỗi ở cấp cao và giải nén tài nguyên bằng cách sử dụng các mẫu để tránh lặp lại mã làm sạch.

Giới thiệu Đơn vị Kiểm tra

Không có thử nghiệm, tái tạo rất đáng sợ. lập một khuôn khổ thử nghiệm đơn vị sớm.

  • Không hợp – lý tưởng cho hệ thống nhúng.
  • CMocka ) – bao gồm ủng hộ chế giễu các mô-đun riêng lẻ.
  • Dây xích — truyền thống nhưng chức năng.

Thử nghiệm đơn vị ghi cho mỗi mô- đun đã được sửa chữa. Dùng khả năng phát triển kiểm tra (TD) để xác định hành vi đã muốn, rồi trả lại hiệu lực cho đến khi qua. Kiểm tra khả năng hỗ trợ hợp lệ nên chạy toàn bộ hệ thống với kết xuất đã biết và mong đợi kết xuất. Tự động toàn bộ các thử nghiệm trong môi trường CN để bắt hồi quy ngay lập tức.

9 Cách thực hiện

Việc phục hồi thường cải thiện hiệu suất, nhưng nó cũng có thể giới thiệu chức năng bên trên (v. d., nhiều chức năng gọi, bọc bộ nhớ định vị). Hồ sơ trước và sau khi thay đổi sử dụng các công cụ như , , hoặc Xcodement. Thay thế phần mềm xác định các đường nóng. Cho phép trình biên dịch tối ưu hoá [FL:47] hoặc [FL:48] và cờ kiến trúc ([FL:49]. Thay thế bằng chức năng sửa đổi chuẩn hoặc chức năng có thể sửa đổi trong tương lai.

Thử thách và kiểm tra

Một chiến lược thử nghiệm giai đoạn là quan trọng khi sửa mã di sản. Hãy theo những bước sau:

  1. Thử ra xâm lược – Chạy dãy thử đã có (nếu có) trước khi tạo thay đổi để thiết lập đường cơ bản. Nếu không có thử nghiệm, hãy ghi lại những thử nghiệm về khói để thực hiện các đường dẫn lõi.
  2. Giá trị tăng dần ) – Sửa đổi một mô- đun một lần. Sau mỗi thay đổi, biên dịch bằng cờ nghiêm ngặt và chạy thử đơn vị. Dùng khả năng điều khiển phiên bản (v. d., Git) với nhỏ, nguyên tử cam kết để bạn có thể phục hồi dễ dàng.
  3. Sự kết hợp phân tích mật mã ) – Thêm Cppcheck và bộ gia sư vào đường ống CN. Điều trị cảnh báo là lỗi để áp dụng chất lượng.
  4. Phân tích ) – Chạy dưới sự điều chỉnh của Valgrind hoặc Asan vào ban đêm để phát hiện các vấn đề về trí nhớ được đưa ra bằng cách sửa đổi.
  5. Thử nghiệm chấp nhận người dùng – triển khai hệ thống đã thỏa mãn về môi trường con xếp lại và nhờ các chuyên gia miền thực hiện các thử nghiệm cuối cùng đến cuối. So sánh bản ghi, thời gian và tài nguyên với bản gốc.

Tự động tạo ra các bước này với một trình phục vụ CN (GitHub Actions, Jenkins, GitLab CI) giảm chi phí hướng dẫn và tạo lòng tin vào tiến trình phục hồi.

Kết luận

Giải mã C không phải là một dự án một lần mà là một sự sửa đổi liên tục. bằng cách điều khiển một cuộc kiểm tra kỹ lưỡng, thiết lập các tiêu chuẩn hiện đại, điều chỉnh cơ sở mã, thay thế các chức năng không an toàn, cải thiện bộ nhớ, và thực hiện kiểm tra nghiêm ngặt, các nhà phát triển có thể biến một khối u mỏng manh thành một hệ thống mạnh mẽ, duy trì. Đầu tư được trả tiền trong mức độ ít khiếm khuyết, tăng tốc độ lên thành thành viên mới, và sự kết hợp mịn hơn với các công cụ và thư viện hiện đại. Bắt đầu cài đặt nhỏ, áp dụng các chiến lược này, và nó sẽ hiệu quả toàn bộ hệ thống mã sẽ đáp ứng các yêu cầu của sự an ninh ngày nay.