Trong tất cả các kịch bản sao chép / di chuyển chuỗi - strcat (), strncat (), strcpy (), strncpy (), v.v. - mọi thứ trở nên tốt hơn nhiều ( an toàn hơn ) nếu một vài phương pháp heuristics đơn giản được thực thi:
1. Luôn NUL-fill (các) bộ đệm của bạn trước khi thêm dữ liệu.
2. Khai báo bộ đệm ký tự là [SIZE + 1], với một hằng số macro.
Ví dụ, đã cho:
#define BUFSIZE 10
char Buffer[BUFSIZE+1] = { 0x00 }; /* The compiler NUL-fills the rest */
chúng ta có thể sử dụng mã như:
memset(Buffer,0x00,sizeof(Buffer));
strncpy(Buffer,BUFSIZE,"12345678901234567890");
tương đối an toàn. Memset () sẽ xuất hiện trước strncpy (), ngay cả khi chúng tôi đã khởi tạo Bộ đệm tại thời điểm biên dịch, vì chúng tôi không biết mã rác nào khác được đặt vào nó trước khi hàm của chúng tôi được gọi. Strncpy () sẽ cắt bớt dữ liệu được sao chép thành "1234567890", và sẽ không kết thúc nó. Tuy nhiên, vì chúng tôi đã lấp đầy NUL toàn bộ bộ đệm - sizeof (Bộ đệm), chứ không phải là BUFSIZE - nên dù sao thì chúng tôi vẫn đảm bảo là một "ngoài phạm vi" cuối cùng chấm dứt NUL, miễn là chúng tôi hạn chế việc ghi của mình bằng BUFSIZE không đổi, thay vì sizeof (Bộ đệm).
Bộ đệm và BUFSIZE cũng hoạt động tốt cho snprintf ():
memset(Buffer,0x00,sizeof(Buffer));
if(snprintf(Buffer,BUFIZE,"Data: %s","Too much data") > BUFSIZE) {
/* Do some error-handling */
} /* If using MFC, you need if(... < 0), instead */
Mặc dù snprintf () đặc biệt chỉ viết các ký tự BUFIZE-1, theo sau là NUL, điều này hoạt động an toàn. Vì vậy, chúng tôi "lãng phí" một byte NUL không liên quan ở cuối Bộ đệm ... chúng tôi ngăn chặn cả điều kiện tràn bộ đệm và chuỗi không kết thúc, với chi phí bộ nhớ khá nhỏ.
Cuộc gọi của tôi trên strcat () và strncat () khó hơn: không sử dụng chúng. Rất khó để sử dụng strcat () một cách an toàn và API cho strncat () phản trực quan đến mức nỗ lực cần thiết để sử dụng nó đúng cách sẽ phủ nhận bất kỳ lợi ích nào. Tôi đề xuất thả vào sau:
#define strncat(target,source,bufsize) snprintf(target,source,"%s%s",target,source)
Thật hấp dẫn để tạo một trình đơn strcat (), nhưng không phải là một ý kiến hay:
#define strcat(target,source) snprintf(target,sizeof(target),"%s%s",target,source)
bởi vì target có thể là một con trỏ (do đó sizeof () không trả về thông tin chúng ta cần). Tôi không có giải pháp "phổ quát" tốt cho các trường hợp strcat () trong mã của bạn.
Một vấn đề mà tôi thường xuyên gặp phải từ các lập trình viên "strFunc () - Recognition" là cố gắng bảo vệ chống tràn bộ đệm bằng cách sử dụng strlen (). Điều này là tốt nếu các nội dung được đảm bảo là kết thúc NUL. Nếu không, bản thân strlen () có thể gây ra lỗi chạy quá bộ đệm (thường dẫn đến vi phạm phân đoạn hoặc tình huống kết xuất lõi khác), trước khi bạn tiếp cận mã "có vấn đề" mà bạn đang cố gắng bảo vệ.