Vấn đề là ở đây:
strncpy(buffer,str,strlen(str));
^^^^^^^^^^^
Nếu chuỗi lớn hơn độ dài của bộ đệm đích, strncpy vẫn sẽ sao chép nó qua. Bạn đang căn cứ số lượng ký tự của chuỗi là số cần sao chép thay vì kích thước của bộ đệm. Cách chính xác để làm điều này là như sau:
strncpy(buffer,str, sizeof(buff) - 1);
buffer[sizeof(buff) - 1] = '\0';
Điều này làm là giới hạn số lượng dữ liệu được sao chép vào kích thước thực của bộ đệm trừ đi một ký tự cho ký tự kết thúc null. Sau đó, chúng tôi đặt byte cuối cùng trong bộ đệm thành ký tự null dưới dạng bảo vệ được thêm vào. Lý do cho điều này là do strncpy sẽ sao chép tối đa n byte, bao gồm cả null kết thúc, nếu strlen (str) <len - 1. Nếu không, thì null không được sao chép và bạn có một kịch bản sự cố vì bây giờ bộ đệm của bạn đã bị lỗi chuỗi.
Hi vọng điêu nay co ich.
EDIT: Sau khi kiểm tra thêm và nhập từ người khác, mã hóa có thể cho chức năng sau:
int func (char *str)
{
char buffer[100];
unsigned short size = sizeof(buffer);
unsigned short len = strlen(str);
if (len > size - 1) return(-1);
memcpy(buffer, str, len + 1);
buffer[size - 1] = '\0';
return(0);
}
Vì chúng ta đã biết độ dài của chuỗi, chúng ta có thể sử dụng memcpy để sao chép chuỗi từ vị trí được tham chiếu bởi str vào bộ đệm. Lưu ý rằng trên mỗi trang hướng dẫn cho strlen (3) (trên hệ thống FreeBSD 9.3), nội dung sau được nêu:
The strlen() function returns the number of characters that precede the
terminating NUL character. The strnlen() function returns either the
same result as strlen() or maxlen, whichever is smaller.
Điều tôi giải thích là độ dài của chuỗi không bao gồm null. Đó là lý do tại sao tôi sao chép len + 1 byte để bao gồm null và kiểm tra kiểm tra để đảm bảo rằng độ dài <kích thước của bộ đệm - 2. Trừ đi một vì bộ đệm bắt đầu ở vị trí 0 và trừ đi một bộ đệm khác để đảm bảo có chỗ trống cho null
EDIT: Hóa ra, kích thước của một cái gì đó bắt đầu bằng 1 trong khi truy cập bắt đầu bằng 0, vì vậy -2 trước đó không chính xác vì nó sẽ trả về lỗi cho bất cứ điều gì> 98 byte nhưng nó phải> 99 byte.
EDIT: Mặc dù câu trả lời về một ký hiệu không dấu thường nói chung là chính xác vì độ dài tối đa có thể được biểu thị là 65.535 ký tự, nhưng điều đó không thực sự quan trọng bởi vì nếu chuỗi dài hơn đó, giá trị sẽ bao quanh. Giống như lấy 75.231 (là 0x000125DF) và che giấu 16 bit hàng đầu mang lại cho bạn 9695 (0x000025DF). Vấn đề duy nhất mà tôi thấy với điều này là 100 ký tự đầu tiên vượt qua 65.535 vì kiểm tra độ dài sẽ cho phép sao chép, nhưng nó sẽ chỉ sao chép tối đa 100 ký tự đầu tiên của chuỗi trong mọi trường hợp và vô hiệu hóa chuỗi . Vì vậy, ngay cả với vấn đề xoay vòng, bộ đệm vẫn sẽ không bị tràn.
Điều này có thể hoặc không tự nó gây ra rủi ro bảo mật tùy thuộc vào nội dung của chuỗi và bạn đang sử dụng nó để làm gì. Nếu đó chỉ là văn bản thẳng mà con người có thể đọc được thì nhìn chung không có vấn đề gì. Bạn chỉ cần có được một chuỗi cắt ngắn. Tuy nhiên, nếu đó là một cái gì đó như một URL hoặc thậm chí là một chuỗi lệnh SQL, bạn có thể gặp vấn đề.